diff options
| author | Jeff Garzik <jeff@garzik.org> | 2006-04-18 05:39:10 -0400 |
|---|---|---|
| committer | Jeff Garzik <jeff@garzik.org> | 2006-04-18 05:39:10 -0400 |
| commit | b2b4b9a7c09ad66e095b13c97946a96f2dc8284e (patch) | |
| tree | fb856b5998df266bd83e6e64b8884287e812845a /drivers/net | |
| parent | 875999c5539999f61a45620aae0c3e5fb1d2b035 (diff) | |
| parent | 4741c336d27dec3ea68a35659abb8dc82b142388 (diff) | |
Merge branch 'upstream'
Diffstat (limited to 'drivers/net')
| -rw-r--r-- | drivers/net/b44.c | 64 | ||||
| -rw-r--r-- | drivers/net/bnx2.c | 2 | ||||
| -rw-r--r-- | drivers/net/hydra.h | 177 | ||||
| -rw-r--r-- | drivers/net/irda/irda-usb.c | 6 | ||||
| -rw-r--r-- | drivers/net/irda/smsc-ircc2.c | 316 | ||||
| -rw-r--r-- | drivers/net/ixgb/ixgb_main.c | 13 | ||||
| -rw-r--r-- | drivers/net/mv643xx_eth.c | 19 | ||||
| -rw-r--r-- | drivers/net/natsemi.c | 2 | ||||
| -rw-r--r-- | drivers/net/pcmcia/axnet_cs.c | 2 | ||||
| -rw-r--r-- | drivers/net/skge.c | 2 | ||||
| -rw-r--r-- | drivers/net/sky2.c | 6 | ||||
| -rw-r--r-- | drivers/net/sky2.h | 2 | ||||
| -rw-r--r-- | drivers/net/starfire.c | 2 | ||||
| -rw-r--r-- | drivers/net/typhoon.c | 2 | ||||
| -rw-r--r-- | drivers/net/via-rhine.c | 7 | ||||
| -rw-r--r-- | drivers/net/wan/Kconfig | 97 | ||||
| -rw-r--r-- | drivers/net/wan/Makefile | 13 | ||||
| -rw-r--r-- | drivers/net/wan/sdla_chdlc.c | 4428 | ||||
| -rw-r--r-- | drivers/net/wan/sdla_fr.c | 5061 | ||||
| -rw-r--r-- | drivers/net/wan/sdla_ft1.c | 345 | ||||
| -rw-r--r-- | drivers/net/wan/sdla_ppp.c | 3430 | ||||
| -rw-r--r-- | drivers/net/wan/sdla_x25.c | 5497 | ||||
| -rw-r--r-- | drivers/net/wan/sdladrv.c | 2314 | ||||
| -rw-r--r-- | drivers/net/wan/sdlamain.c | 1346 | ||||
| -rw-r--r-- | drivers/net/wan/wanpipe_multppp.c | 2358 |
25 files changed, 335 insertions, 25176 deletions
diff --git a/drivers/net/b44.c b/drivers/net/b44.c index c4e12b5cbb92..3d306681919e 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | * | 2 | * |
| 3 | * Copyright (C) 2002 David S. Miller (davem@redhat.com) | 3 | * Copyright (C) 2002 David S. Miller (davem@redhat.com) |
| 4 | * Fixed by Pekka Pietikainen (pp@ee.oulu.fi) | 4 | * Fixed by Pekka Pietikainen (pp@ee.oulu.fi) |
| 5 | * Copyright (C) 2006 Broadcom Corporation. | ||
| 5 | * | 6 | * |
| 6 | * Distribute under GPL. | 7 | * Distribute under GPL. |
| 7 | */ | 8 | */ |
| @@ -28,8 +29,8 @@ | |||
| 28 | 29 | ||
| 29 | #define DRV_MODULE_NAME "b44" | 30 | #define DRV_MODULE_NAME "b44" |
| 30 | #define PFX DRV_MODULE_NAME ": " | 31 | #define PFX DRV_MODULE_NAME ": " |
| 31 | #define DRV_MODULE_VERSION "0.97" | 32 | #define DRV_MODULE_VERSION "1.00" |
| 32 | #define DRV_MODULE_RELDATE "Nov 30, 2005" | 33 | #define DRV_MODULE_RELDATE "Apr 7, 2006" |
| 33 | 34 | ||
| 34 | #define B44_DEF_MSG_ENABLE \ | 35 | #define B44_DEF_MSG_ENABLE \ |
| 35 | (NETIF_MSG_DRV | \ | 36 | (NETIF_MSG_DRV | \ |
| @@ -136,7 +137,7 @@ static inline unsigned long br32(const struct b44 *bp, unsigned long reg) | |||
| 136 | return readl(bp->regs + reg); | 137 | return readl(bp->regs + reg); |
| 137 | } | 138 | } |
| 138 | 139 | ||
| 139 | static inline void bw32(const struct b44 *bp, | 140 | static inline void bw32(const struct b44 *bp, |
| 140 | unsigned long reg, unsigned long val) | 141 | unsigned long reg, unsigned long val) |
| 141 | { | 142 | { |
| 142 | writel(val, bp->regs + reg); | 143 | writel(val, bp->regs + reg); |
| @@ -286,13 +287,13 @@ static void __b44_cam_write(struct b44 *bp, unsigned char *data, int index) | |||
| 286 | val |= ((u32) data[4]) << 8; | 287 | val |= ((u32) data[4]) << 8; |
| 287 | val |= ((u32) data[5]) << 0; | 288 | val |= ((u32) data[5]) << 0; |
| 288 | bw32(bp, B44_CAM_DATA_LO, val); | 289 | bw32(bp, B44_CAM_DATA_LO, val); |
| 289 | val = (CAM_DATA_HI_VALID | | 290 | val = (CAM_DATA_HI_VALID | |
| 290 | (((u32) data[0]) << 8) | | 291 | (((u32) data[0]) << 8) | |
| 291 | (((u32) data[1]) << 0)); | 292 | (((u32) data[1]) << 0)); |
| 292 | bw32(bp, B44_CAM_DATA_HI, val); | 293 | bw32(bp, B44_CAM_DATA_HI, val); |
| 293 | bw32(bp, B44_CAM_CTRL, (CAM_CTRL_WRITE | | 294 | bw32(bp, B44_CAM_CTRL, (CAM_CTRL_WRITE | |
| 294 | (index << CAM_CTRL_INDEX_SHIFT))); | 295 | (index << CAM_CTRL_INDEX_SHIFT))); |
| 295 | b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1); | 296 | b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1); |
| 296 | } | 297 | } |
| 297 | 298 | ||
| 298 | static inline void __b44_disable_ints(struct b44 *bp) | 299 | static inline void __b44_disable_ints(struct b44 *bp) |
| @@ -410,25 +411,18 @@ static void __b44_set_flow_ctrl(struct b44 *bp, u32 pause_flags) | |||
| 410 | 411 | ||
| 411 | static void b44_set_flow_ctrl(struct b44 *bp, u32 local, u32 remote) | 412 | static void b44_set_flow_ctrl(struct b44 *bp, u32 local, u32 remote) |
| 412 | { | 413 | { |
| 413 | u32 pause_enab = bp->flags & (B44_FLAG_TX_PAUSE | | 414 | u32 pause_enab = 0; |
| 414 | B44_FLAG_RX_PAUSE); | ||
| 415 | 415 | ||
| 416 | if (local & ADVERTISE_PAUSE_CAP) { | 416 | /* The driver supports only rx pause by default because |
| 417 | if (local & ADVERTISE_PAUSE_ASYM) { | 417 | the b44 mac tx pause mechanism generates excessive |
| 418 | if (remote & LPA_PAUSE_CAP) | 418 | pause frames. |
| 419 | pause_enab |= (B44_FLAG_TX_PAUSE | | 419 | Use ethtool to turn on b44 tx pause if necessary. |
| 420 | B44_FLAG_RX_PAUSE); | 420 | */ |
| 421 | else if (remote & LPA_PAUSE_ASYM) | 421 | if ((local & ADVERTISE_PAUSE_CAP) && |
| 422 | pause_enab |= B44_FLAG_RX_PAUSE; | 422 | (local & ADVERTISE_PAUSE_ASYM)){ |
| 423 | } else { | 423 | if ((remote & LPA_PAUSE_ASYM) && |
| 424 | if (remote & LPA_PAUSE_CAP) | 424 | !(remote & LPA_PAUSE_CAP)) |
| 425 | pause_enab |= (B44_FLAG_TX_PAUSE | | 425 | pause_enab |= B44_FLAG_RX_PAUSE; |
| 426 | B44_FLAG_RX_PAUSE); | ||
| 427 | } | ||
| 428 | } else if (local & ADVERTISE_PAUSE_ASYM) { | ||
| 429 | if ((remote & LPA_PAUSE_CAP) && | ||
| 430 | (remote & LPA_PAUSE_ASYM)) | ||
| 431 | pause_enab |= B44_FLAG_TX_PAUSE; | ||
| 432 | } | 426 | } |
| 433 | 427 | ||
| 434 | __b44_set_flow_ctrl(bp, pause_enab); | 428 | __b44_set_flow_ctrl(bp, pause_enab); |
| @@ -1063,7 +1057,7 @@ static int b44_change_mtu(struct net_device *dev, int new_mtu) | |||
| 1063 | spin_unlock_irq(&bp->lock); | 1057 | spin_unlock_irq(&bp->lock); |
| 1064 | 1058 | ||
| 1065 | b44_enable_ints(bp); | 1059 | b44_enable_ints(bp); |
| 1066 | 1060 | ||
| 1067 | return 0; | 1061 | return 0; |
| 1068 | } | 1062 | } |
| 1069 | 1063 | ||
| @@ -1381,7 +1375,7 @@ static void b44_init_hw(struct b44 *bp) | |||
| 1381 | bw32(bp, B44_DMARX_ADDR, bp->rx_ring_dma + bp->dma_offset); | 1375 | bw32(bp, B44_DMARX_ADDR, bp->rx_ring_dma + bp->dma_offset); |
| 1382 | 1376 | ||
| 1383 | bw32(bp, B44_DMARX_PTR, bp->rx_pending); | 1377 | bw32(bp, B44_DMARX_PTR, bp->rx_pending); |
| 1384 | bp->rx_prod = bp->rx_pending; | 1378 | bp->rx_prod = bp->rx_pending; |
| 1385 | 1379 | ||
| 1386 | bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ); | 1380 | bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ); |
| 1387 | 1381 | ||
| @@ -1553,9 +1547,9 @@ static void __b44_set_rx_mode(struct net_device *dev) | |||
| 1553 | val |= RXCONFIG_ALLMULTI; | 1547 | val |= RXCONFIG_ALLMULTI; |
| 1554 | else | 1548 | else |
| 1555 | i = __b44_load_mcast(bp, dev); | 1549 | i = __b44_load_mcast(bp, dev); |
| 1556 | 1550 | ||
| 1557 | for (; i < 64; i++) { | 1551 | for (; i < 64; i++) { |
| 1558 | __b44_cam_write(bp, zero, i); | 1552 | __b44_cam_write(bp, zero, i); |
| 1559 | } | 1553 | } |
| 1560 | bw32(bp, B44_RXCONFIG, val); | 1554 | bw32(bp, B44_RXCONFIG, val); |
| 1561 | val = br32(bp, B44_CAM_CTRL); | 1555 | val = br32(bp, B44_CAM_CTRL); |
| @@ -1737,7 +1731,7 @@ static int b44_set_ringparam(struct net_device *dev, | |||
| 1737 | spin_unlock_irq(&bp->lock); | 1731 | spin_unlock_irq(&bp->lock); |
| 1738 | 1732 | ||
| 1739 | b44_enable_ints(bp); | 1733 | b44_enable_ints(bp); |
| 1740 | 1734 | ||
| 1741 | return 0; | 1735 | return 0; |
| 1742 | } | 1736 | } |
| 1743 | 1737 | ||
| @@ -1782,7 +1776,7 @@ static int b44_set_pauseparam(struct net_device *dev, | |||
| 1782 | spin_unlock_irq(&bp->lock); | 1776 | spin_unlock_irq(&bp->lock); |
| 1783 | 1777 | ||
| 1784 | b44_enable_ints(bp); | 1778 | b44_enable_ints(bp); |
| 1785 | 1779 | ||
| 1786 | return 0; | 1780 | return 0; |
| 1787 | } | 1781 | } |
| 1788 | 1782 | ||
| @@ -1898,7 +1892,7 @@ static int __devinit b44_get_invariants(struct b44 *bp) | |||
| 1898 | bp->core_unit = ssb_core_unit(bp); | 1892 | bp->core_unit = ssb_core_unit(bp); |
| 1899 | bp->dma_offset = SB_PCI_DMA; | 1893 | bp->dma_offset = SB_PCI_DMA; |
| 1900 | 1894 | ||
| 1901 | /* XXX - really required? | 1895 | /* XXX - really required? |
| 1902 | bp->flags |= B44_FLAG_BUGGY_TXPTR; | 1896 | bp->flags |= B44_FLAG_BUGGY_TXPTR; |
| 1903 | */ | 1897 | */ |
| 1904 | out: | 1898 | out: |
| @@ -1946,7 +1940,7 @@ static int __devinit b44_init_one(struct pci_dev *pdev, | |||
| 1946 | "aborting.\n"); | 1940 | "aborting.\n"); |
| 1947 | goto err_out_free_res; | 1941 | goto err_out_free_res; |
| 1948 | } | 1942 | } |
| 1949 | 1943 | ||
| 1950 | err = pci_set_consistent_dma_mask(pdev, (u64) B44_DMA_MASK); | 1944 | err = pci_set_consistent_dma_mask(pdev, (u64) B44_DMA_MASK); |
| 1951 | if (err) { | 1945 | if (err) { |
| 1952 | printk(KERN_ERR PFX "No usable DMA configuration, " | 1946 | printk(KERN_ERR PFX "No usable DMA configuration, " |
| @@ -2041,9 +2035,9 @@ static int __devinit b44_init_one(struct pci_dev *pdev, | |||
| 2041 | 2035 | ||
| 2042 | pci_save_state(bp->pdev); | 2036 | pci_save_state(bp->pdev); |
| 2043 | 2037 | ||
| 2044 | /* Chip reset provides power to the b44 MAC & PCI cores, which | 2038 | /* Chip reset provides power to the b44 MAC & PCI cores, which |
| 2045 | * is necessary for MAC register access. | 2039 | * is necessary for MAC register access. |
| 2046 | */ | 2040 | */ |
| 2047 | b44_chip_reset(bp); | 2041 | b44_chip_reset(bp); |
| 2048 | 2042 | ||
| 2049 | printk(KERN_INFO "%s: Broadcom 4400 10/100BaseT Ethernet ", dev->name); | 2043 | printk(KERN_INFO "%s: Broadcom 4400 10/100BaseT Ethernet ", dev->name); |
| @@ -2091,10 +2085,10 @@ static int b44_suspend(struct pci_dev *pdev, pm_message_t state) | |||
| 2091 | 2085 | ||
| 2092 | del_timer_sync(&bp->timer); | 2086 | del_timer_sync(&bp->timer); |
| 2093 | 2087 | ||
| 2094 | spin_lock_irq(&bp->lock); | 2088 | spin_lock_irq(&bp->lock); |
| 2095 | 2089 | ||
| 2096 | b44_halt(bp); | 2090 | b44_halt(bp); |
| 2097 | netif_carrier_off(bp->dev); | 2091 | netif_carrier_off(bp->dev); |
| 2098 | netif_device_detach(bp->dev); | 2092 | netif_device_detach(bp->dev); |
| 2099 | b44_free_rings(bp); | 2093 | b44_free_rings(bp); |
| 2100 | 2094 | ||
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 2671da20a496..5ca99e26660a 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c | |||
| @@ -63,7 +63,7 @@ | |||
| 63 | /* Time in jiffies before concluding the transmitter is hung. */ | 63 | /* Time in jiffies before concluding the transmitter is hung. */ |
| 64 | #define TX_TIMEOUT (5*HZ) | 64 | #define TX_TIMEOUT (5*HZ) |
| 65 | 65 | ||
| 66 | static char version[] __devinitdata = | 66 | static const char version[] __devinitdata = |
| 67 | "Broadcom NetXtreme II Gigabit Ethernet Driver " DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; | 67 | "Broadcom NetXtreme II Gigabit Ethernet Driver " DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; |
| 68 | 68 | ||
| 69 | MODULE_AUTHOR("Michael Chan <mchan@broadcom.com>"); | 69 | MODULE_AUTHOR("Michael Chan <mchan@broadcom.com>"); |
diff --git a/drivers/net/hydra.h b/drivers/net/hydra.h deleted file mode 100644 index 37414146258d..000000000000 --- a/drivers/net/hydra.h +++ /dev/null | |||
| @@ -1,177 +0,0 @@ | |||
| 1 | /* $Linux: hydra.h,v 1.0 1994/10/26 02:03:47 cgd Exp $ */ | ||
| 2 | |||
| 3 | /* | ||
| 4 | * Copyright (c) 1994 Timo Rossi | ||
| 5 | * All rights reserved. | ||
| 6 | * | ||
| 7 | * Redistribution and use in source and binary forms, with or without | ||
| 8 | * modification, are permitted provided that the following conditions | ||
| 9 | * are met: | ||
| 10 | * 1. Redistributions of source code must retain the above copyright | ||
| 11 | * notice, this list of conditions and the following disclaimer. | ||
| 12 | * 2. Redistributions in binary form must reproduce the above copyright | ||
| 13 | * notice, this list of conditions and the following disclaimer in the | ||
| 14 | * documentation and/or other materials provided with the distribution. | ||
| 15 | * 3. All advertising materials mentioning features or use of this software | ||
| 16 | * must display the following acknowledgement: | ||
| 17 | * This product includes software developed by Timo Rossi | ||
| 18 | * 4. The name of the author may not be used to endorse or promote products | ||
| 19 | * derived from this software without specific prior written permission | ||
| 20 | * | ||
| 21 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
| 22 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
| 23 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
| 24 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
| 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
| 26 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
| 30 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| 31 | */ | ||
| 32 | |||
| 33 | /* | ||
| 34 | * The Hydra Systems card uses the National Semiconductor | ||
| 35 | * 8390 NIC (Network Interface Controller) chip, located | ||
| 36 | * at card base address + 0xffe1. NIC registers are accessible | ||
| 37 | * only at odd byte addresses, so the register offsets must | ||
| 38 | * be multiplied by two. | ||
| 39 | * | ||
| 40 | * Card address PROM is located at card base + 0xffc0 (even byte addresses) | ||
| 41 | * | ||
| 42 | * RAM starts at the card base address, and is 16K or 64K. | ||
| 43 | * The current Amiga NetBSD hydra driver is hardwired for 16K. | ||
| 44 | * It seems that the RAM should be accessed as words or longwords only. | ||
| 45 | * | ||
| 46 | */ | ||
| 47 | |||
| 48 | /* adapted for Linux by Topi Kanerva 03/29/95 | ||
| 49 | with original author's permission */ | ||
| 50 | |||
| 51 | #define HYDRA_NIC_BASE 0xffe1 | ||
| 52 | |||
| 53 | /* Page0 registers */ | ||
| 54 | |||
| 55 | #define NIC_CR 0 /* Command register */ | ||
| 56 | #define NIC_PSTART (1*2) /* Page start (write) */ | ||
| 57 | #define NIC_PSTOP (2*2) /* Page stop (write) */ | ||
| 58 | #define NIC_BNDRY (3*2) /* Boundary pointer */ | ||
| 59 | #define NIC_TSR (4*2) /* Transmit status (read) */ | ||
| 60 | #define NIC_TPSR (4*2) /* Transmit page start (write) */ | ||
| 61 | #define NIC_NCR (5*2) /* Number of collisions, read */ | ||
| 62 | #define NIC_TBCR0 (5*2) /* Transmit byte count low (write) */ | ||
| 63 | #define NIC_FIFO (6*2) /* FIFO reg. (read) */ | ||
| 64 | #define NIC_TBCR1 (6*2) /* Transmit byte count high (write) */ | ||
| 65 | #define NIC_ISR (7*2) /* Interrupt status register */ | ||
| 66 | #define NIC_RBCR0 (0xa*2) /* Remote byte count low (write) */ | ||
| 67 | #define NIC_RBCR1 (0xb*2) /* Remote byte count high (write) */ | ||
| 68 | #define NIC_RSR (0xc*2) /* Receive status (read) */ | ||
| 69 | #define NIC_RCR (0xc*2) /* Receive config (write) */ | ||
| 70 | #define NIC_CNTR0 (0xd*2) /* Frame alignment error count (read) */ | ||
| 71 | #define NIC_TCR (0xd*2) /* Transmit config (write) */ | ||
| 72 | #define NIC_CNTR1 (0xe*2) /* CRC error counter (read) */ | ||
| 73 | #define NIC_DCR (0xe*2) /* Data config (write) */ | ||
| 74 | #define NIC_CNTR2 (0xf*2) /* missed packet counter (read) */ | ||
| 75 | #define NIC_IMR (0xf*2) /* Interrupt mask reg. (write) */ | ||
| 76 | |||
| 77 | /* Page1 registers */ | ||
| 78 | |||
| 79 | #define NIC_PAR0 (1*2) /* Physical address */ | ||
| 80 | #define NIC_PAR1 (2*2) | ||
| 81 | #define NIC_PAR2 (3*2) | ||
| 82 | #define NIC_PAR3 (4*2) | ||
| 83 | #define NIC_PAR4 (5*2) | ||
| 84 | #define NIC_PAR5 (6*2) | ||
| 85 | #define NIC_CURR (7*2) /* Current RX ring-buffer page */ | ||
| 86 | #define NIC_MAR0 (8*2) /* Multicast address */ | ||
| 87 | #define NIC_MAR1 (9*2) | ||
| 88 | #define NIC_MAR2 (0xa*2) | ||
| 89 | #define NIC_MAR3 (0xb*2) | ||
| 90 | #define NIC_MAR4 (0xc*2) | ||
| 91 | #define NIC_MAR5 (0xd*2) | ||
| 92 | #define NIC_MAR6 (0xe*2) | ||
| 93 | #define NIC_MAR7 (0xf*2) | ||
| 94 | |||
| 95 | /* Command register definitions */ | ||
| 96 | |||
| 97 | #define CR_STOP 0x01 /* Stop -- software reset command */ | ||
| 98 | #define CR_START 0x02 /* Start */ | ||
| 99 | #define CR_TXP 0x04 /* Transmit packet */ | ||
| 100 | |||
| 101 | #define CR_RD0 0x08 /* Remote DMA cmd */ | ||
| 102 | #define CR_RD1 0x10 | ||
| 103 | #define CR_RD2 0x20 | ||
| 104 | |||
| 105 | #define CR_NODMA CR_RD2 | ||
| 106 | |||
| 107 | #define CR_PS0 0x40 /* Page select */ | ||
| 108 | #define CR_PS1 0x80 | ||
| 109 | |||
| 110 | #define CR_PAGE0 0 | ||
| 111 | #define CR_PAGE1 CR_PS0 | ||
| 112 | #define CR_PAGE2 CR_PS1 | ||
| 113 | |||
| 114 | /* Interrupt status reg. definitions */ | ||
| 115 | |||
| 116 | #define ISR_PRX 0x01 /* Packet received without errors */ | ||
| 117 | #define ISR_PTX 0x02 /* Packet transmitted without errors */ | ||
| 118 | #define ISR_RXE 0x04 /* Receive error */ | ||
| 119 | #define ISR_TXE 0x08 /* Transmit error */ | ||
| 120 | #define ISR_OVW 0x10 /* Ring buffer overrun */ | ||
| 121 | #define ISR_CNT 0x20 /* Counter overflow */ | ||
| 122 | #define ISR_RDC 0x40 /* Remote DMA compile */ | ||
| 123 | #define ISR_RST 0x80 /* Reset status */ | ||
| 124 | |||
| 125 | /* Data config reg. definitions */ | ||
| 126 | |||
| 127 | #define DCR_WTS 0x01 /* Word transfer select */ | ||
| 128 | #define DCR_BOS 0x02 /* Byte order select */ | ||
| 129 | #define DCR_LAS 0x04 /* Long address select */ | ||
| 130 | #define DCR_LS 0x08 /* Loopback select */ | ||
| 131 | #define DCR_AR 0x10 /* Auto-init remote */ | ||
| 132 | #define DCR_FT0 0x20 /* FIFO threshold select */ | ||
| 133 | #define DCR_FT1 0x40 | ||
| 134 | |||
| 135 | /* Transmit config reg. definitions */ | ||
| 136 | |||
| 137 | #define TCR_CRC 0x01 /* Inhibit CRC */ | ||
| 138 | #define TCR_LB0 0x02 /* Loopback control */ | ||
| 139 | #define TCR_LB1 0x04 | ||
| 140 | #define TCR_ATD 0x08 /* Auto transmit disable */ | ||
| 141 | #define TCR_OFST 0x10 /* Collision offset enable */ | ||
| 142 | |||
| 143 | /* Transmit status reg. definitions */ | ||
| 144 | |||
| 145 | #define TSR_PTX 0x01 /* Packet transmitted */ | ||
| 146 | #define TSR_COL 0x04 /* Transmit collided */ | ||
| 147 | #define TSR_ABT 0x08 /* Transmit aborted */ | ||
| 148 | #define TSR_CRS 0x10 /* Carrier sense lost */ | ||
| 149 | #define TSR_FU 0x20 /* FIFO underrun */ | ||
| 150 | #define TSR_CDH 0x40 /* CD Heartbeat */ | ||
| 151 | #define TSR_OWC 0x80 /* Out of Window Collision */ | ||
| 152 | |||
| 153 | /* Receiver config register definitions */ | ||
| 154 | |||
| 155 | #define RCR_SEP 0x01 /* Save errored packets */ | ||
| 156 | #define RCR_AR 0x02 /* Accept runt packets */ | ||
| 157 | #define RCR_AB 0x04 /* Accept broadcast */ | ||
| 158 | #define RCR_AM 0x08 /* Accept multicast */ | ||
| 159 | #define RCR_PRO 0x10 /* Promiscuous mode */ | ||
| 160 | #define RCR_MON 0x20 /* Monitor mode */ | ||
| 161 | |||
| 162 | /* Receiver status register definitions */ | ||
| 163 | |||
| 164 | #define RSR_PRX 0x01 /* Packet received without error */ | ||
| 165 | #define RSR_CRC 0x02 /* CRC error */ | ||
| 166 | #define RSR_FAE 0x04 /* Frame alignment error */ | ||
| 167 | #define RSR_FO 0x08 /* FIFO overrun */ | ||
| 168 | #define RSR_MPA 0x10 /* Missed packet */ | ||
| 169 | #define RSR_PHY 0x20 /* Physical address */ | ||
| 170 | #define RSR_DIS 0x40 /* Received disabled */ | ||
| 171 | #define RSR_DFR 0x80 /* Deferring (jabber) */ | ||
| 172 | |||
| 173 | /* Hydra System card address PROM offset */ | ||
| 174 | |||
| 175 | #define HYDRA_ADDRPROM 0xffc0 | ||
| 176 | |||
| 177 | |||
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 606243d11793..96bdb73c2283 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c | |||
| @@ -1815,14 +1815,14 @@ static int irda_usb_probe(struct usb_interface *intf, | |||
| 1815 | self->needspatch = (ret < 0); | 1815 | self->needspatch = (ret < 0); |
| 1816 | if (ret < 0) { | 1816 | if (ret < 0) { |
| 1817 | printk("patch_device failed\n"); | 1817 | printk("patch_device failed\n"); |
| 1818 | goto err_out_4; | 1818 | goto err_out_5; |
| 1819 | } | 1819 | } |
| 1820 | 1820 | ||
| 1821 | /* replace IrDA class descriptor with what patched device is now reporting */ | 1821 | /* replace IrDA class descriptor with what patched device is now reporting */ |
| 1822 | irda_desc = irda_usb_find_class_desc (self->usbintf); | 1822 | irda_desc = irda_usb_find_class_desc (self->usbintf); |
| 1823 | if (irda_desc == NULL) { | 1823 | if (irda_desc == NULL) { |
| 1824 | ret = -ENODEV; | 1824 | ret = -ENODEV; |
| 1825 | goto err_out_4; | 1825 | goto err_out_5; |
| 1826 | } | 1826 | } |
| 1827 | if (self->irda_desc) | 1827 | if (self->irda_desc) |
| 1828 | kfree (self->irda_desc); | 1828 | kfree (self->irda_desc); |
| @@ -1832,6 +1832,8 @@ static int irda_usb_probe(struct usb_interface *intf, | |||
| 1832 | 1832 | ||
| 1833 | return 0; | 1833 | return 0; |
| 1834 | 1834 | ||
| 1835 | err_out_5: | ||
| 1836 | unregister_netdev(self->netdev); | ||
| 1835 | err_out_4: | 1837 | err_out_4: |
| 1836 | kfree(self->speed_buff); | 1838 | kfree(self->speed_buff); |
| 1837 | err_out_3: | 1839 | err_out_3: |
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index bbcfc8ec35a1..58f76cefbc83 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c | |||
| @@ -225,6 +225,8 @@ static int __init smsc_superio_lpc(unsigned short cfg_base); | |||
| 225 | #ifdef CONFIG_PCI | 225 | #ifdef CONFIG_PCI |
| 226 | static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf); | 226 | static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf); |
| 227 | static int __init preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); | 227 | static int __init preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); |
| 228 | static void __init preconfigure_ali_port(struct pci_dev *dev, | ||
| 229 | unsigned short port); | ||
| 228 | static int __init preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); | 230 | static int __init preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); |
| 229 | static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, | 231 | static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, |
| 230 | unsigned short ircc_fir, | 232 | unsigned short ircc_fir, |
| @@ -2327,9 +2329,14 @@ static int __init smsc_superio_lpc(unsigned short cfg_base) | |||
| 2327 | * pre-configuration not properly done by the BIOS (especially laptops) | 2329 | * pre-configuration not properly done by the BIOS (especially laptops) |
| 2328 | * This code is based in part on smcinit.c, tosh1800-smcinit.c | 2330 | * This code is based in part on smcinit.c, tosh1800-smcinit.c |
| 2329 | * and tosh2450-smcinit.c. The table lists the device entries | 2331 | * and tosh2450-smcinit.c. The table lists the device entries |
| 2330 | * for ISA bridges with an LPC (Local Peripheral Configurator) | 2332 | * for ISA bridges with an LPC (Low Pin Count) controller which |
| 2331 | * that are in turn used to configure the SMSC device with default | 2333 | * handles the communication with the SMSC device. After the LPC |
| 2332 | * SIR and FIR I/O ports, DMA and IRQ. | 2334 | * controller is initialized through PCI, the SMSC device is initialized |
| 2335 | * through a dedicated port in the ISA port-mapped I/O area, this latter | ||
| 2336 | * area is used to configure the SMSC device with default | ||
| 2337 | * SIR and FIR I/O ports, DMA and IRQ. Different vendors have | ||
| 2338 | * used different sets of parameters and different control port | ||
| 2339 | * addresses making a subsystem device table necessary. | ||
| 2333 | */ | 2340 | */ |
| 2334 | #ifdef CONFIG_PCI | 2341 | #ifdef CONFIG_PCI |
| 2335 | #define PCIID_VENDOR_INTEL 0x8086 | 2342 | #define PCIID_VENDOR_INTEL 0x8086 |
| @@ -2340,9 +2347,10 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __dev | |||
| 2340 | .device = 0x24cc, | 2347 | .device = 0x24cc, |
| 2341 | .subvendor = 0x103c, | 2348 | .subvendor = 0x103c, |
| 2342 | .subdevice = 0x088c, | 2349 | .subdevice = 0x088c, |
| 2343 | .sir_io = 0x02f8, /* Quite certain these are the same for nc8000 as for nc6000 */ | 2350 | /* Quite certain these are the same for nc8000 as for nc6000 */ |
| 2351 | .sir_io = 0x02f8, | ||
| 2344 | .fir_io = 0x0130, | 2352 | .fir_io = 0x0130, |
| 2345 | .fir_irq = 0x09, | 2353 | .fir_irq = 0x05, |
| 2346 | .fir_dma = 0x03, | 2354 | .fir_dma = 0x03, |
| 2347 | .cfg_base = 0x004e, | 2355 | .cfg_base = 0x004e, |
| 2348 | .preconfigure = preconfigure_through_82801, | 2356 | .preconfigure = preconfigure_through_82801, |
| @@ -2355,60 +2363,79 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __dev | |||
| 2355 | .subdevice = 0x0890, | 2363 | .subdevice = 0x0890, |
| 2356 | .sir_io = 0x02f8, | 2364 | .sir_io = 0x02f8, |
| 2357 | .fir_io = 0x0130, | 2365 | .fir_io = 0x0130, |
| 2358 | .fir_irq = 0x09, | 2366 | .fir_irq = 0x05, |
| 2359 | .fir_dma = 0x03, | 2367 | .fir_dma = 0x03, |
| 2360 | .cfg_base = 0x004e, | 2368 | .cfg_base = 0x004e, |
| 2361 | .preconfigure = preconfigure_through_82801, | 2369 | .preconfigure = preconfigure_through_82801, |
| 2362 | .name = "HP nc6000", | 2370 | .name = "HP nc6000", |
| 2363 | }, | 2371 | }, |
| 2364 | { | 2372 | { |
| 2365 | .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge */ | 2373 | /* Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge */ |
| 2374 | .vendor = PCIID_VENDOR_INTEL, | ||
| 2366 | .device = 0x24c0, | 2375 | .device = 0x24c0, |
| 2367 | .subvendor = 0x1179, | 2376 | .subvendor = 0x1179, |
| 2368 | .subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */ | 2377 | .subdevice = 0xffff, /* 0xffff is "any" */ |
| 2369 | .sir_io = 0x03f8, | 2378 | .sir_io = 0x03f8, |
| 2370 | .fir_io = 0x0130, | 2379 | .fir_io = 0x0130, |
| 2371 | .fir_irq = 0x07, | 2380 | .fir_irq = 0x07, |
| 2372 | .fir_dma = 0x01, | 2381 | .fir_dma = 0x01, |
| 2373 | .cfg_base = 0x002e, | 2382 | .cfg_base = 0x002e, |
| 2374 | .preconfigure = preconfigure_through_82801, | 2383 | .preconfigure = preconfigure_through_82801, |
| 2375 | .name = "Toshiba Satellite 2450", | 2384 | .name = "Toshiba laptop with Intel 82801DB/DBL LPC bridge", |
| 2376 | }, | 2385 | }, |
| 2377 | { | 2386 | { |
| 2378 | .vendor = PCIID_VENDOR_INTEL, /* Intel 82801CAM ISA bridge */ | 2387 | .vendor = PCIID_VENDOR_INTEL, /* Intel 82801CAM ISA bridge */ |
| 2379 | .device = 0x248c, /* Some use 24cc? */ | 2388 | .device = 0x248c, |
| 2380 | .subvendor = 0x1179, | 2389 | .subvendor = 0x1179, |
| 2381 | .subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */ | 2390 | .subdevice = 0xffff, /* 0xffff is "any" */ |
| 2382 | .sir_io = 0x03f8, | 2391 | .sir_io = 0x03f8, |
| 2383 | .fir_io = 0x0130, | 2392 | .fir_io = 0x0130, |
| 2384 | .fir_irq = 0x03, | 2393 | .fir_irq = 0x03, |
| 2385 | .fir_dma = 0x03, | 2394 | .fir_dma = 0x03, |
| 2386 | .cfg_base = 0x002e, | 2395 | .cfg_base = 0x002e, |
| 2387 | .preconfigure = preconfigure_through_82801, | 2396 | .preconfigure = preconfigure_through_82801, |
| 2388 | .name = "Toshiba Satellite 5100/5200, Tecra 9100", | 2397 | .name = "Toshiba laptop with Intel 82801CAM ISA bridge", |
| 2389 | }, | 2398 | }, |
| 2390 | { | 2399 | { |
| 2391 | .vendor = PCIID_VENDOR_ALI, /* ALi M1533/M1535 PCI to ISA Bridge [Aladdin IV/V/V+] */ | 2400 | /* 82801DBM (ICH4-M) LPC Interface Bridge */ |
| 2401 | .vendor = PCIID_VENDOR_INTEL, | ||
| 2402 | .device = 0x24cc, | ||
| 2403 | .subvendor = 0x1179, | ||
| 2404 | .subdevice = 0xffff, /* 0xffff is "any" */ | ||
| 2405 | .sir_io = 0x03f8, | ||
| 2406 | .fir_io = 0x0130, | ||
| 2407 | .fir_irq = 0x03, | ||
| 2408 | .fir_dma = 0x03, | ||
| 2409 | .cfg_base = 0x002e, | ||
| 2410 | .preconfigure = preconfigure_through_82801, | ||
| 2411 | .name = "Toshiba laptop with Intel 8281DBM LPC bridge", | ||
| 2412 | }, | ||
| 2413 | { | ||
| 2414 | /* ALi M1533/M1535 PCI to ISA Bridge [Aladdin IV/V/V+] */ | ||
| 2415 | .vendor = PCIID_VENDOR_ALI, | ||
| 2392 | .device = 0x1533, | 2416 | .device = 0x1533, |
| 2393 | .subvendor = 0x1179, | 2417 | .subvendor = 0x1179, |
| 2394 | .subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */ | 2418 | .subdevice = 0xffff, /* 0xffff is "any" */ |
| 2395 | .sir_io = 0x02e8, | 2419 | .sir_io = 0x02e8, |
| 2396 | .fir_io = 0x02f8, | 2420 | .fir_io = 0x02f8, |
| 2397 | .fir_irq = 0x07, | 2421 | .fir_irq = 0x07, |
| 2398 | .fir_dma = 0x03, | 2422 | .fir_dma = 0x03, |
| 2399 | .cfg_base = 0x002e, | 2423 | .cfg_base = 0x002e, |
| 2400 | .preconfigure = preconfigure_through_ali, | 2424 | .preconfigure = preconfigure_through_ali, |
| 2401 | .name = "Toshiba Satellite 1800", | 2425 | .name = "Toshiba laptop with ALi ISA bridge", |
| 2402 | }, | 2426 | }, |
| 2403 | { } // Terminator | 2427 | { } // Terminator |
| 2404 | }; | 2428 | }; |
| 2405 | 2429 | ||
| 2406 | 2430 | ||
| 2407 | /* | 2431 | /* |
| 2408 | * This sets up the basic SMSC parameters (FIR port, SIR port, FIR DMA, FIR IRQ) | 2432 | * This sets up the basic SMSC parameters |
| 2433 | * (FIR port, SIR port, FIR DMA, FIR IRQ) | ||
| 2409 | * through the chip configuration port. | 2434 | * through the chip configuration port. |
| 2410 | */ | 2435 | */ |
| 2411 | static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf) | 2436 | static int __init preconfigure_smsc_chip(struct |
| 2437 | smsc_ircc_subsystem_configuration | ||
| 2438 | *conf) | ||
| 2412 | { | 2439 | { |
| 2413 | unsigned short iobase = conf->cfg_base; | 2440 | unsigned short iobase = conf->cfg_base; |
| 2414 | unsigned char tmpbyte; | 2441 | unsigned char tmpbyte; |
| @@ -2416,7 +2443,9 @@ static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuratio | |||
| 2416 | outb(LPC47N227_CFGACCESSKEY, iobase); // enter configuration state | 2443 | outb(LPC47N227_CFGACCESSKEY, iobase); // enter configuration state |
| 2417 | outb(SMSCSIOFLAT_DEVICEID_REG, iobase); // set for device ID | 2444 | outb(SMSCSIOFLAT_DEVICEID_REG, iobase); // set for device ID |
| 2418 | tmpbyte = inb(iobase +1); // Read device ID | 2445 | tmpbyte = inb(iobase +1); // Read device ID |
| 2419 | IRDA_DEBUG(0, "Detected Chip id: 0x%02x, setting up registers...\n",tmpbyte); | 2446 | IRDA_DEBUG(0, |
| 2447 | "Detected Chip id: 0x%02x, setting up registers...\n", | ||
| 2448 | tmpbyte); | ||
| 2420 | 2449 | ||
| 2421 | /* Disable UART1 and set up SIR I/O port */ | 2450 | /* Disable UART1 and set up SIR I/O port */ |
| 2422 | outb(0x24, iobase); // select CR24 - UART1 base addr | 2451 | outb(0x24, iobase); // select CR24 - UART1 base addr |
| @@ -2426,6 +2455,7 @@ static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuratio | |||
| 2426 | tmpbyte = inb(iobase + 1); | 2455 | tmpbyte = inb(iobase + 1); |
| 2427 | if (tmpbyte != (conf->sir_io >> 2) ) { | 2456 | if (tmpbyte != (conf->sir_io >> 2) ) { |
| 2428 | IRDA_WARNING("ERROR: could not configure SIR ioport.\n"); | 2457 | IRDA_WARNING("ERROR: could not configure SIR ioport.\n"); |
| 2458 | IRDA_WARNING("Try to supply ircc_cfg argument.\n"); | ||
| 2429 | return -ENXIO; | 2459 | return -ENXIO; |
| 2430 | } | 2460 | } |
| 2431 | 2461 | ||
| @@ -2461,7 +2491,8 @@ static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuratio | |||
| 2461 | 2491 | ||
| 2462 | outb(SMSCSIOFLAT_UARTMODE0C_REG, iobase); // CR0C - UART mode | 2492 | outb(SMSCSIOFLAT_UARTMODE0C_REG, iobase); // CR0C - UART mode |
| 2463 | tmpbyte = inb(iobase + 1); | 2493 | tmpbyte = inb(iobase + 1); |
| 2464 | tmpbyte &= ~SMSCSIOFLAT_UART2MODE_MASK | SMSCSIOFLAT_UART2MODE_VAL_IRDA; | 2494 | tmpbyte &= ~SMSCSIOFLAT_UART2MODE_MASK | |
| 2495 | SMSCSIOFLAT_UART2MODE_VAL_IRDA; | ||
| 2465 | outb(tmpbyte, iobase + 1); // enable IrDA (HPSIR) mode, high speed | 2496 | outb(tmpbyte, iobase + 1); // enable IrDA (HPSIR) mode, high speed |
| 2466 | 2497 | ||
| 2467 | outb(LPC47N227_APMBOOTDRIVE_REG, iobase); // CR07 - Auto Pwr Mgt/boot drive sel | 2498 | outb(LPC47N227_APMBOOTDRIVE_REG, iobase); // CR07 - Auto Pwr Mgt/boot drive sel |
| @@ -2486,53 +2517,226 @@ static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuratio | |||
| 2486 | return 0; | 2517 | return 0; |
| 2487 | } | 2518 | } |
| 2488 | 2519 | ||
| 2489 | /* 82801CAM registers */ | 2520 | /* 82801CAM generic registers */ |
| 2490 | #define VID 0x00 | 2521 | #define VID 0x00 |
| 2491 | #define DID 0x02 | 2522 | #define DID 0x02 |
| 2492 | #define PIRQA_ROUT 0x60 | 2523 | #define PIRQ_A_D_ROUT 0x60 |
| 2524 | #define SIRQ_CNTL 0x64 | ||
| 2525 | #define PIRQ_E_H_ROUT 0x68 | ||
| 2493 | #define PCI_DMA_C 0x90 | 2526 | #define PCI_DMA_C 0x90 |
| 2527 | /* LPC-specific registers */ | ||
| 2494 | #define COM_DEC 0xe0 | 2528 | #define COM_DEC 0xe0 |
| 2529 | #define GEN1_DEC 0xe4 | ||
| 2495 | #define LPC_EN 0xe6 | 2530 | #define LPC_EN 0xe6 |
| 2496 | #define GEN2_DEC 0xec | 2531 | #define GEN2_DEC 0xec |
| 2497 | /* | 2532 | /* |
| 2498 | * Sets up the I/O range using the 82801CAM ISA bridge, 82801DBM LPC bridge or | 2533 | * Sets up the I/O range using the 82801CAM ISA bridge, 82801DBM LPC bridge |
| 2499 | * Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge. They all work the same way! | 2534 | * or Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge. |
| 2535 | * They all work the same way! | ||
| 2500 | */ | 2536 | */ |
| 2501 | static int __init preconfigure_through_82801(struct pci_dev *dev, | 2537 | static int __init preconfigure_through_82801(struct pci_dev *dev, |
| 2502 | struct smsc_ircc_subsystem_configuration *conf) | 2538 | struct |
| 2539 | smsc_ircc_subsystem_configuration | ||
| 2540 | *conf) | ||
| 2503 | { | 2541 | { |
| 2504 | unsigned short tmpword; | 2542 | unsigned short tmpword; |
| 2505 | int ret; | 2543 | unsigned char tmpbyte; |
| 2506 | 2544 | ||
| 2507 | IRDA_MESSAGE("Setting up the SMSC device via the 82801 controller.\n"); | 2545 | IRDA_MESSAGE("Setting up Intel 82801 controller and SMSC device\n"); |
| 2508 | pci_write_config_byte(dev, COM_DEC, 0x10); | 2546 | /* |
| 2547 | * Select the range for the COMA COM port (SIR) | ||
| 2548 | * Register COM_DEC: | ||
| 2549 | * Bit 7: reserved | ||
| 2550 | * Bit 6-4, COMB decode range | ||
| 2551 | * Bit 3: reserved | ||
| 2552 | * Bit 2-0, COMA decode range | ||
| 2553 | * | ||
| 2554 | * Decode ranges: | ||
| 2555 | * 000 = 0x3f8-0x3ff (COM1) | ||
| 2556 | * 001 = 0x2f8-0x2ff (COM2) | ||
| 2557 | * 010 = 0x220-0x227 | ||
| 2558 | * 011 = 0x228-0x22f | ||
| 2559 | * 100 = 0x238-0x23f | ||
| 2560 | * 101 = 0x2e8-0x2ef (COM4) | ||
| 2561 | * 110 = 0x338-0x33f | ||
| 2562 | * 111 = 0x3e8-0x3ef (COM3) | ||
| 2563 | */ | ||
| 2564 | pci_read_config_byte(dev, COM_DEC, &tmpbyte); | ||
| 2565 | tmpbyte &= 0xf8; /* mask COMA bits */ | ||
| 2566 | switch(conf->sir_io) { | ||
| 2567 | case 0x3f8: | ||
| 2568 | tmpbyte |= 0x00; | ||
| 2569 | break; | ||
| 2570 | case 0x2f8: | ||
| 2571 | tmpbyte |= 0x01; | ||
| 2572 | break; | ||
| 2573 | case 0x220: | ||
| 2574 | tmpbyte |= 0x02; | ||
| 2575 | break; | ||
| 2576 | case 0x228: | ||
| 2577 | tmpbyte |= 0x03; | ||
| 2578 | break; | ||
| 2579 | case 0x238: | ||
| 2580 | tmpbyte |= 0x04; | ||
| 2581 | break; | ||
| 2582 | case 0x2e8: | ||
| 2583 | tmpbyte |= 0x05; | ||
| 2584 | break; | ||
| 2585 | case 0x338: | ||
| 2586 | tmpbyte |= 0x06; | ||
| 2587 | break; | ||
| 2588 | case 0x3e8: | ||
| 2589 | tmpbyte |= 0x07; | ||
| 2590 | break; | ||
| 2591 | default: | ||
| 2592 | tmpbyte |= 0x01; /* COM2 default */ | ||
| 2593 | } | ||
| 2594 | IRDA_DEBUG(1, "COM_DEC (write): 0x%02x\n", tmpbyte); | ||
| 2595 | pci_write_config_byte(dev, COM_DEC, tmpbyte); | ||
| 2509 | 2596 | ||
| 2510 | /* Enable LPC */ | 2597 | /* Enable Low Pin Count interface */ |
| 2511 | pci_read_config_word(dev, LPC_EN, &tmpword); /* LPC_EN register */ | 2598 | pci_read_config_word(dev, LPC_EN, &tmpword); |
| 2512 | tmpword &= 0xfffd; /* mask bit 1 */ | 2599 | /* These seem to be set up at all times, |
| 2513 | tmpword |= 0x0001; /* set bit 0 : COMA addr range enable */ | 2600 | * just make sure it is properly set. |
| 2601 | */ | ||
| 2602 | switch(conf->cfg_base) { | ||
| 2603 | case 0x04e: | ||
| 2604 | tmpword |= 0x2000; | ||
| 2605 | break; | ||
| 2606 | case 0x02e: | ||
| 2607 | tmpword |= 0x1000; | ||
| 2608 | break; | ||
| 2609 | case 0x062: | ||
| 2610 | tmpword |= 0x0800; | ||
| 2611 | break; | ||
| 2612 | case 0x060: | ||
| 2613 | tmpword |= 0x0400; | ||
| 2614 | break; | ||
| 2615 | default: | ||
| 2616 | IRDA_WARNING("Uncommon I/O base address: 0x%04x\n", | ||
| 2617 | conf->cfg_base); | ||
| 2618 | break; | ||
| 2619 | } | ||
| 2620 | tmpword &= 0xfffd; /* disable LPC COMB */ | ||
| 2621 | tmpword |= 0x0001; /* set bit 0 : enable LPC COMA addr range (GEN2) */ | ||
| 2622 | IRDA_DEBUG(1, "LPC_EN (write): 0x%04x\n", tmpword); | ||
| 2514 | pci_write_config_word(dev, LPC_EN, tmpword); | 2623 | pci_write_config_word(dev, LPC_EN, tmpword); |
| 2515 | 2624 | ||
| 2516 | /* Setup DMA */ | 2625 | /* |
| 2517 | pci_write_config_word(dev, PCI_DMA_C, 0xc0c0); /* LPC I/F DMA on, channel 3 -- rtm (?? PCI DMA ?) */ | 2626 | * Configure LPC DMA channel |
| 2518 | pci_write_config_word(dev, GEN2_DEC, 0x131); /* LPC I/F 2nd decode range */ | 2627 | * PCI_DMA_C bits: |
| 2628 | * Bit 15-14: DMA channel 7 select | ||
| 2629 | * Bit 13-12: DMA channel 6 select | ||
| 2630 | * Bit 11-10: DMA channel 5 select | ||
| 2631 | * Bit 9-8: Reserved | ||
| 2632 | * Bit 7-6: DMA channel 3 select | ||
| 2633 | * Bit 5-4: DMA channel 2 select | ||
| 2634 | * Bit 3-2: DMA channel 1 select | ||
| 2635 | * Bit 1-0: DMA channel 0 select | ||
| 2636 | * 00 = Reserved value | ||
| 2637 | * 01 = PC/PCI DMA | ||
| 2638 | * 10 = Reserved value | ||
| 2639 | * 11 = LPC I/F DMA | ||
| 2640 | */ | ||
| 2641 | pci_read_config_word(dev, PCI_DMA_C, &tmpword); | ||
| 2642 | switch(conf->fir_dma) { | ||
| 2643 | case 0x07: | ||
| 2644 | tmpword |= 0xc000; | ||
| 2645 | break; | ||
| 2646 | case 0x06: | ||
| 2647 | tmpword |= 0x3000; | ||
| 2648 | break; | ||
| 2649 | case 0x05: | ||
| 2650 | tmpword |= 0x0c00; | ||
| 2651 | break; | ||
| 2652 | case 0x03: | ||
| 2653 | tmpword |= 0x00c0; | ||
| 2654 | break; | ||
| 2655 | case 0x02: | ||
| 2656 | tmpword |= 0x0030; | ||
| 2657 | break; | ||
| 2658 | case 0x01: | ||
| 2659 | tmpword |= 0x000c; | ||
| 2660 | break; | ||
| 2661 | case 0x00: | ||
| 2662 | tmpword |= 0x0003; | ||
| 2663 | break; | ||
| 2664 | default: | ||
| 2665 | break; /* do not change settings */ | ||
| 2666 | } | ||
| 2667 | IRDA_DEBUG(1, "PCI_DMA_C (write): 0x%04x\n", tmpword); | ||
| 2668 | pci_write_config_word(dev, PCI_DMA_C, tmpword); | ||
| 2669 | |||
| 2670 | /* | ||
| 2671 | * GEN2_DEC bits: | ||
| 2672 | * Bit 15-4: Generic I/O range | ||
| 2673 | * Bit 3-1: reserved (read as 0) | ||
| 2674 | * Bit 0: enable GEN2 range on LPC I/F | ||
| 2675 | */ | ||
| 2676 | tmpword = conf->fir_io & 0xfff8; | ||
| 2677 | tmpword |= 0x0001; | ||
| 2678 | IRDA_DEBUG(1, "GEN2_DEC (write): 0x%04x\n", tmpword); | ||
| 2679 | pci_write_config_word(dev, GEN2_DEC, tmpword); | ||
| 2519 | 2680 | ||
| 2520 | /* Pre-configure chip */ | 2681 | /* Pre-configure chip */ |
| 2521 | ret = preconfigure_smsc_chip(conf); | 2682 | return preconfigure_smsc_chip(conf); |
| 2683 | } | ||
| 2522 | 2684 | ||
| 2523 | /* Disable LPC */ | 2685 | /* |
| 2524 | pci_read_config_word(dev, LPC_EN, &tmpword); /* LPC_EN register */ | 2686 | * Pre-configure a certain port on the ALi 1533 bridge. |
| 2525 | tmpword &= 0xfffc; /* mask bit 1 and bit 0, COMA addr range disable */ | 2687 | * This is based on reverse-engineering since ALi does not |
| 2526 | pci_write_config_word(dev, LPC_EN, tmpword); | 2688 | * provide any data sheet for the 1533 chip. |
| 2527 | return ret; | 2689 | */ |
| 2690 | static void __init preconfigure_ali_port(struct pci_dev *dev, | ||
| 2691 | unsigned short port) | ||
| 2692 | { | ||
| 2693 | unsigned char reg; | ||
| 2694 | /* These bits obviously control the different ports */ | ||
| 2695 | unsigned char mask; | ||
| 2696 | unsigned char tmpbyte; | ||
| 2697 | |||
| 2698 | switch(port) { | ||
| 2699 | case 0x0130: | ||
| 2700 | case 0x0178: | ||
| 2701 | reg = 0xb0; | ||
| 2702 | mask = 0x80; | ||
| 2703 | break; | ||
| 2704 | case 0x03f8: | ||
| 2705 | reg = 0xb4; | ||
| 2706 | mask = 0x80; | ||
| 2707 | break; | ||
| 2708 | case 0x02f8: | ||
| 2709 | reg = 0xb4; | ||
| 2710 | mask = 0x30; | ||
| 2711 | break; | ||
| 2712 | case 0x02e8: | ||
| 2713 | reg = 0xb4; | ||
| 2714 | mask = 0x08; | ||
| 2715 | break; | ||
| 2716 | default: | ||
| 2717 | IRDA_ERROR("Failed to configure unsupported port on ALi 1533 bridge: 0x%04x\n", port); | ||
| 2718 | return; | ||
| 2719 | } | ||
| 2720 | |||
| 2721 | pci_read_config_byte(dev, reg, &tmpbyte); | ||
| 2722 | /* Turn on the right bits */ | ||
| 2723 | tmpbyte |= mask; | ||
| 2724 | pci_write_config_byte(dev, reg, tmpbyte); | ||
| 2725 | IRDA_MESSAGE("Activated ALi 1533 ISA bridge port 0x%04x.\n", port); | ||
| 2726 | return; | ||
| 2528 | } | 2727 | } |
| 2529 | 2728 | ||
| 2530 | static int __init preconfigure_through_ali(struct pci_dev *dev, | 2729 | static int __init preconfigure_through_ali(struct pci_dev *dev, |
| 2531 | struct smsc_ircc_subsystem_configuration *conf) | 2730 | struct |
| 2731 | smsc_ircc_subsystem_configuration | ||
| 2732 | *conf) | ||
| 2532 | { | 2733 | { |
| 2533 | /* TODO: put in ALi 1533 configuration here. */ | 2734 | /* Configure the two ports on the ALi 1533 */ |
| 2534 | IRDA_MESSAGE("SORRY: %s has an unsupported bridge controller (ALi): not pre-configured.\n", conf->name); | 2735 | preconfigure_ali_port(dev, conf->sir_io); |
| 2535 | return -ENODEV; | 2736 | preconfigure_ali_port(dev, conf->fir_io); |
| 2737 | |||
| 2738 | /* Pre-configure chip */ | ||
| 2739 | return preconfigure_smsc_chip(conf); | ||
| 2536 | } | 2740 | } |
| 2537 | 2741 | ||
| 2538 | static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, | 2742 | static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, |
| @@ -2552,9 +2756,10 @@ static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, | |||
| 2552 | struct smsc_ircc_subsystem_configuration *conf; | 2756 | struct smsc_ircc_subsystem_configuration *conf; |
| 2553 | 2757 | ||
| 2554 | /* | 2758 | /* |
| 2555 | * Cache the subsystem vendor/device: some manufacturers fail to set | 2759 | * Cache the subsystem vendor/device: |
| 2556 | * this for all components, so we save it in case there is just | 2760 | * some manufacturers fail to set this for all components, |
| 2557 | * 0x0000 0x0000 on the device we want to check. | 2761 | * so we save it in case there is just 0x0000 0x0000 on the |
| 2762 | * device we want to check. | ||
| 2558 | */ | 2763 | */ |
| 2559 | if (dev->subsystem_vendor != 0x0000U) { | 2764 | if (dev->subsystem_vendor != 0x0000U) { |
| 2560 | ss_vendor = dev->subsystem_vendor; | 2765 | ss_vendor = dev->subsystem_vendor; |
| @@ -2564,13 +2769,20 @@ static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, | |||
| 2564 | for( ; conf->subvendor; conf++) { | 2769 | for( ; conf->subvendor; conf++) { |
| 2565 | if(conf->vendor == dev->vendor && | 2770 | if(conf->vendor == dev->vendor && |
| 2566 | conf->device == dev->device && | 2771 | conf->device == dev->device && |
| 2567 | conf->subvendor == ss_vendor && /* Sometimes these are cached values */ | 2772 | conf->subvendor == ss_vendor && |
| 2568 | (conf->subdevice == ss_device || conf->subdevice == 0xffff)) { | 2773 | /* Sometimes these are cached values */ |
| 2569 | struct smsc_ircc_subsystem_configuration tmpconf; | 2774 | (conf->subdevice == ss_device || |
| 2775 | conf->subdevice == 0xffff)) { | ||
| 2776 | struct smsc_ircc_subsystem_configuration | ||
| 2777 | tmpconf; | ||
| 2570 | 2778 | ||
| 2571 | memcpy(&tmpconf, conf, sizeof(struct smsc_ircc_subsystem_configuration)); | 2779 | memcpy(&tmpconf, conf, |
| 2780 | sizeof(struct smsc_ircc_subsystem_configuration)); | ||
| 2572 | 2781 | ||
| 2573 | /* Override the default values with anything passed in as parameter */ | 2782 | /* |
| 2783 | * Override the default values with anything | ||
| 2784 | * passed in as parameter | ||
| 2785 | */ | ||
| 2574 | if (ircc_cfg != 0) | 2786 | if (ircc_cfg != 0) |
| 2575 | tmpconf.cfg_base = ircc_cfg; | 2787 | tmpconf.cfg_base = ircc_cfg; |
| 2576 | if (ircc_fir != 0) | 2788 | if (ircc_fir != 0) |
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index f9f77e4f5965..cfd67d812f0d 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c | |||
| @@ -357,18 +357,20 @@ ixgb_probe(struct pci_dev *pdev, | |||
| 357 | if((err = pci_enable_device(pdev))) | 357 | if((err = pci_enable_device(pdev))) |
| 358 | return err; | 358 | return err; |
| 359 | 359 | ||
| 360 | if(!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) { | 360 | if(!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK)) && |
| 361 | !(err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))) { | ||
| 361 | pci_using_dac = 1; | 362 | pci_using_dac = 1; |
| 362 | } else { | 363 | } else { |
| 363 | if((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK))) { | 364 | if((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) || |
| 365 | (err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))) { | ||
| 364 | IXGB_ERR("No usable DMA configuration, aborting\n"); | 366 | IXGB_ERR("No usable DMA configuration, aborting\n"); |
| 365 | return err; | 367 | goto err_dma_mask; |
| 366 | } | 368 | } |
| 367 | pci_using_dac = 0; | 369 | pci_using_dac = 0; |
| 368 | } | 370 | } |
| 369 | 371 | ||
| 370 | if((err = pci_request_regions(pdev, ixgb_driver_name))) | 372 | if((err = pci_request_regions(pdev, ixgb_driver_name))) |
| 371 | return err; | 373 | goto err_request_regions; |
| 372 | 374 | ||
| 373 | pci_set_master(pdev); | 375 | pci_set_master(pdev); |
| 374 | 376 | ||
| @@ -502,6 +504,9 @@ err_ioremap: | |||
| 502 | free_netdev(netdev); | 504 | free_netdev(netdev); |
| 503 | err_alloc_etherdev: | 505 | err_alloc_etherdev: |
| 504 | pci_release_regions(pdev); | 506 | pci_release_regions(pdev); |
| 507 | err_request_regions: | ||
| 508 | err_dma_mask: | ||
| 509 | pci_disable_device(pdev); | ||
| 505 | return err; | 510 | return err; |
| 506 | } | 511 | } |
| 507 | 512 | ||
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 9f2661355a4a..ea62a3e7d586 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c | |||
| @@ -281,10 +281,16 @@ static void mv643xx_eth_tx_timeout_task(struct net_device *dev) | |||
| 281 | { | 281 | { |
| 282 | struct mv643xx_private *mp = netdev_priv(dev); | 282 | struct mv643xx_private *mp = netdev_priv(dev); |
| 283 | 283 | ||
| 284 | netif_device_detach(dev); | 284 | if (!netif_running(dev)) |
| 285 | return; | ||
| 286 | |||
| 287 | netif_stop_queue(dev); | ||
| 288 | |||
| 285 | eth_port_reset(mp->port_num); | 289 | eth_port_reset(mp->port_num); |
| 286 | eth_port_start(dev); | 290 | eth_port_start(dev); |
| 287 | netif_device_attach(dev); | 291 | |
| 292 | if (mp->tx_ring_size - mp->tx_desc_count >= MAX_DESCS_PER_SKB) | ||
| 293 | netif_wake_queue(dev); | ||
| 288 | } | 294 | } |
| 289 | 295 | ||
| 290 | /** | 296 | /** |
| @@ -552,9 +558,9 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id, | |||
| 552 | #else | 558 | #else |
| 553 | if (eth_int_cause & ETH_INT_CAUSE_RX) | 559 | if (eth_int_cause & ETH_INT_CAUSE_RX) |
| 554 | mv643xx_eth_receive_queue(dev, INT_MAX); | 560 | mv643xx_eth_receive_queue(dev, INT_MAX); |
| 561 | #endif | ||
| 555 | if (eth_int_cause_ext & ETH_INT_CAUSE_TX) | 562 | if (eth_int_cause_ext & ETH_INT_CAUSE_TX) |
| 556 | mv643xx_eth_free_completed_tx_descs(dev); | 563 | mv643xx_eth_free_completed_tx_descs(dev); |
| 557 | #endif | ||
| 558 | 564 | ||
| 559 | /* | 565 | /* |
| 560 | * If no real interrupt occured, exit. | 566 | * If no real interrupt occured, exit. |
| @@ -1186,7 +1192,12 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 1186 | 1192 | ||
| 1187 | BUG_ON(netif_queue_stopped(dev)); | 1193 | BUG_ON(netif_queue_stopped(dev)); |
| 1188 | BUG_ON(skb == NULL); | 1194 | BUG_ON(skb == NULL); |
| 1189 | BUG_ON(mp->tx_ring_size - mp->tx_desc_count < MAX_DESCS_PER_SKB); | 1195 | |
| 1196 | if (mp->tx_ring_size - mp->tx_desc_count < MAX_DESCS_PER_SKB) { | ||
| 1197 | printk(KERN_ERR "%s: transmit with queue full\n", dev->name); | ||
| 1198 | netif_stop_queue(dev); | ||
| 1199 | return 1; | ||
| 1200 | } | ||
| 1190 | 1201 | ||
| 1191 | if (has_tiny_unaligned_frags(skb)) { | 1202 | if (has_tiny_unaligned_frags(skb)) { |
| 1192 | if ((skb_linearize(skb, GFP_ATOMIC) != 0)) { | 1203 | if ((skb_linearize(skb, GFP_ATOMIC) != 0)) { |
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 7826afbb9db9..90627756d6fa 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c | |||
| @@ -238,7 +238,7 @@ static int full_duplex[MAX_UNITS]; | |||
| 238 | #define NATSEMI_RX_LIMIT 2046 /* maximum supported by hardware */ | 238 | #define NATSEMI_RX_LIMIT 2046 /* maximum supported by hardware */ |
| 239 | 239 | ||
| 240 | /* These identify the driver base version and may not be removed. */ | 240 | /* These identify the driver base version and may not be removed. */ |
| 241 | static char version[] __devinitdata = | 241 | static const char version[] __devinitdata = |
| 242 | KERN_INFO DRV_NAME " dp8381x driver, version " | 242 | KERN_INFO DRV_NAME " dp8381x driver, version " |
| 243 | DRV_VERSION ", " DRV_RELDATE "\n" | 243 | DRV_VERSION ", " DRV_RELDATE "\n" |
| 244 | KERN_INFO " originally by Donald Becker <becker@scyld.com>\n" | 244 | KERN_INFO " originally by Donald Becker <becker@scyld.com>\n" |
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 56233afcb2b3..448a09488529 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c | |||
| @@ -1560,7 +1560,7 @@ static void ei_receive(struct net_device *dev) | |||
| 1560 | 1560 | ||
| 1561 | static void ei_rx_overrun(struct net_device *dev) | 1561 | static void ei_rx_overrun(struct net_device *dev) |
| 1562 | { | 1562 | { |
| 1563 | axnet_dev_t *info = (axnet_dev_t *)dev; | 1563 | axnet_dev_t *info = PRIV(dev); |
| 1564 | long e8390_base = dev->base_addr; | 1564 | long e8390_base = dev->base_addr; |
| 1565 | unsigned char was_txing, must_resend = 0; | 1565 | unsigned char was_txing, must_resend = 0; |
| 1566 | struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); | 1566 | struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); |
diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 35dbf05c7f06..a70c2b0cc104 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c | |||
| @@ -78,6 +78,8 @@ static const struct pci_device_id skge_id_table[] = { | |||
| 78 | { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE) }, | 78 | { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE) }, |
| 79 | { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_YU) }, | 79 | { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_YU) }, |
| 80 | { PCI_DEVICE(PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_DGE510T), }, | 80 | { PCI_DEVICE(PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_DGE510T), }, |
| 81 | { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b00) }, | ||
| 82 | { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b01) }, | ||
| 81 | { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4320) }, | 83 | { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4320) }, |
| 82 | { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5005) }, /* Belkin */ | 84 | { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5005) }, /* Belkin */ |
| 83 | { PCI_DEVICE(PCI_VENDOR_ID_CNET, PCI_DEVICE_ID_CNET_GIGACARD) }, | 85 | { PCI_DEVICE(PCI_VENDOR_ID_CNET, PCI_DEVICE_ID_CNET_GIGACARD) }, |
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 68f9c206a620..67b0eab16589 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c | |||
| @@ -99,8 +99,6 @@ MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)"); | |||
| 99 | static const struct pci_device_id sky2_id_table[] = { | 99 | static const struct pci_device_id sky2_id_table[] = { |
| 100 | { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) }, | 100 | { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) }, |
| 101 | { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) }, | 101 | { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) }, |
| 102 | { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b00) }, | ||
| 103 | { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b01) }, | ||
| 104 | { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4340) }, | 102 | { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4340) }, |
| 105 | { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4341) }, | 103 | { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4341) }, |
| 106 | { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4342) }, | 104 | { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4342) }, |
| @@ -579,8 +577,8 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port) | |||
| 579 | reg = gma_read16(hw, port, GM_PHY_ADDR); | 577 | reg = gma_read16(hw, port, GM_PHY_ADDR); |
| 580 | gma_write16(hw, port, GM_PHY_ADDR, reg | GM_PAR_MIB_CLR); | 578 | gma_write16(hw, port, GM_PHY_ADDR, reg | GM_PAR_MIB_CLR); |
| 581 | 579 | ||
| 582 | for (i = 0; i < GM_MIB_CNT_SIZE; i++) | 580 | for (i = GM_MIB_CNT_BASE; i <= GM_MIB_CNT_END; i += 4) |
| 583 | gma_read16(hw, port, GM_MIB_CNT_BASE + 8 * i); | 581 | gma_read16(hw, port, i); |
| 584 | gma_write16(hw, port, GM_PHY_ADDR, reg); | 582 | gma_write16(hw, port, GM_PHY_ADDR, reg); |
| 585 | 583 | ||
| 586 | /* transmit control */ | 584 | /* transmit control */ |
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 62532b4e45c5..89dd18cd12f0 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h | |||
| @@ -1375,7 +1375,7 @@ enum { | |||
| 1375 | GM_PHY_ADDR = 0x0088, /* 16 bit r/w GPHY Address Register */ | 1375 | GM_PHY_ADDR = 0x0088, /* 16 bit r/w GPHY Address Register */ |
| 1376 | /* MIB Counters */ | 1376 | /* MIB Counters */ |
| 1377 | GM_MIB_CNT_BASE = 0x0100, /* Base Address of MIB Counters */ | 1377 | GM_MIB_CNT_BASE = 0x0100, /* Base Address of MIB Counters */ |
| 1378 | GM_MIB_CNT_SIZE = 256, | 1378 | GM_MIB_CNT_END = 0x025C, /* Last MIB counter */ |
| 1379 | }; | 1379 | }; |
| 1380 | 1380 | ||
| 1381 | 1381 | ||
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 45ad036733e2..9b7805be21da 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c | |||
| @@ -335,7 +335,7 @@ do { \ | |||
| 335 | 335 | ||
| 336 | 336 | ||
| 337 | /* These identify the driver base version and may not be removed. */ | 337 | /* These identify the driver base version and may not be removed. */ |
| 338 | static char version[] __devinitdata = | 338 | static const char version[] __devinitdata = |
| 339 | KERN_INFO "starfire.c:v1.03 7/26/2000 Written by Donald Becker <becker@scyld.com>\n" | 339 | KERN_INFO "starfire.c:v1.03 7/26/2000 Written by Donald Becker <becker@scyld.com>\n" |
| 340 | KERN_INFO " (unofficial 2.2/2.4 kernel port, version " DRV_VERSION ", " DRV_RELDATE ")\n"; | 340 | KERN_INFO " (unofficial 2.2/2.4 kernel port, version " DRV_VERSION ", " DRV_RELDATE ")\n"; |
| 341 | 341 | ||
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index c1ce87a5f8d3..d9258d42090c 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c | |||
| @@ -134,7 +134,7 @@ static const int multicast_filter_limit = 32; | |||
| 134 | #include "typhoon.h" | 134 | #include "typhoon.h" |
| 135 | #include "typhoon-firmware.h" | 135 | #include "typhoon-firmware.h" |
| 136 | 136 | ||
| 137 | static char version[] __devinitdata = | 137 | static const char version[] __devinitdata = |
| 138 | "typhoon.c: version " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; | 138 | "typhoon.c: version " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; |
| 139 | 139 | ||
| 140 | MODULE_AUTHOR("David Dillow <dave@thedillows.org>"); | 140 | MODULE_AUTHOR("David Dillow <dave@thedillows.org>"); |
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index a9b2150909d6..6a23964c1317 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c | |||
| @@ -469,7 +469,7 @@ struct rhine_private { | |||
| 469 | struct sk_buff *tx_skbuff[TX_RING_SIZE]; | 469 | struct sk_buff *tx_skbuff[TX_RING_SIZE]; |
| 470 | dma_addr_t tx_skbuff_dma[TX_RING_SIZE]; | 470 | dma_addr_t tx_skbuff_dma[TX_RING_SIZE]; |
| 471 | 471 | ||
| 472 | /* Tx bounce buffers */ | 472 | /* Tx bounce buffers (Rhine-I only) */ |
| 473 | unsigned char *tx_buf[TX_RING_SIZE]; | 473 | unsigned char *tx_buf[TX_RING_SIZE]; |
| 474 | unsigned char *tx_bufs; | 474 | unsigned char *tx_bufs; |
| 475 | dma_addr_t tx_bufs_dma; | 475 | dma_addr_t tx_bufs_dma; |
| @@ -1043,7 +1043,8 @@ static void alloc_tbufs(struct net_device* dev) | |||
| 1043 | rp->tx_ring[i].desc_length = cpu_to_le32(TXDESC); | 1043 | rp->tx_ring[i].desc_length = cpu_to_le32(TXDESC); |
| 1044 | next += sizeof(struct tx_desc); | 1044 | next += sizeof(struct tx_desc); |
| 1045 | rp->tx_ring[i].next_desc = cpu_to_le32(next); | 1045 | rp->tx_ring[i].next_desc = cpu_to_le32(next); |
| 1046 | rp->tx_buf[i] = &rp->tx_bufs[i * PKT_BUF_SZ]; | 1046 | if (rp->quirks & rqRhineI) |
| 1047 | rp->tx_buf[i] = &rp->tx_bufs[i * PKT_BUF_SZ]; | ||
| 1047 | } | 1048 | } |
| 1048 | rp->tx_ring[i-1].next_desc = cpu_to_le32(rp->tx_ring_dma); | 1049 | rp->tx_ring[i-1].next_desc = cpu_to_le32(rp->tx_ring_dma); |
| 1049 | 1050 | ||
| @@ -1091,7 +1092,7 @@ static void rhine_check_media(struct net_device *dev, unsigned int init_media) | |||
| 1091 | } | 1092 | } |
| 1092 | 1093 | ||
| 1093 | /* Called after status of force_media possibly changed */ | 1094 | /* Called after status of force_media possibly changed */ |
| 1094 | void rhine_set_carrier(struct mii_if_info *mii) | 1095 | static void rhine_set_carrier(struct mii_if_info *mii) |
| 1095 | { | 1096 | { |
| 1096 | if (mii->force_media) { | 1097 | if (mii->force_media) { |
| 1097 | /* autoneg is off: Link is always assumed to be up */ | 1098 | /* autoneg is off: Link is always assumed to be up */ |
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index 883cf7da10fc..b5328b0ff927 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig | |||
| @@ -410,103 +410,6 @@ config WAN_ROUTER_DRIVERS | |||
| 410 | 410 | ||
| 411 | If unsure, say N. | 411 | If unsure, say N. |
| 412 | 412 | ||
| 413 | config VENDOR_SANGOMA | ||
| 414 | tristate "Sangoma WANPIPE(tm) multiprotocol cards" | ||
| 415 | depends on WAN_ROUTER_DRIVERS && WAN_ROUTER && (PCI || ISA) && BROKEN | ||
| 416 | ---help--- | ||
| 417 | Driver for S514-PCI/ISA Synchronous Data Link Adapters (SDLA). | ||
| 418 | |||
| 419 | WANPIPE from Sangoma Technologies Inc. <http://www.sangoma.com/> | ||
| 420 | is a family of intelligent multiprotocol WAN adapters with data | ||
| 421 | transfer rates up to 4Mbps. Cards support: | ||
| 422 | |||
| 423 | - X.25, Frame Relay, PPP, Cisco HDLC protocols. | ||
| 424 | |||
| 425 | - API for protocols like HDLC (LAPB), HDLC Streaming, X.25, | ||
| 426 | Frame Relay and BiSync. | ||
| 427 | |||
| 428 | - Ethernet Bridging over Frame Relay protocol. | ||
| 429 | |||
| 430 | - MULTILINK PPP | ||
| 431 | |||
| 432 | - Async PPP (Modem Dialup) | ||
| 433 | |||
| 434 | The next questions will ask you about the protocols you want | ||
| 435 | the driver to support. | ||
| 436 | |||
| 437 | If you have one or more of these cards, say M to this option; | ||
| 438 | and read <file:Documentation/networking/wan-router.txt>. | ||
| 439 | |||
| 440 | To compile this driver as a module, choose M here: the | ||
| 441 | module will be called wanpipe. | ||
| 442 | |||
| 443 | config WANPIPE_CHDLC | ||
| 444 | bool "WANPIPE Cisco HDLC support" | ||
| 445 | depends on VENDOR_SANGOMA | ||
| 446 | ---help--- | ||
| 447 | Connect a WANPIPE card to a leased line using the Cisco HDLC. | ||
| 448 | |||
| 449 | - Supports Dual Port Cisco HDLC on the S514-PCI/S508-ISA cards | ||
| 450 | which allows user to build applications using the HDLC streaming API. | ||
| 451 | |||
| 452 | - CHDLC Streaming MULTILINK PPP that can bind multiple WANPIPE T1 | ||
| 453 | cards into a single logical channel. | ||
| 454 | |||
| 455 | Say Y and the Cisco HDLC support, HDLC streaming API and | ||
| 456 | MULTILINK PPP will be included in the driver. | ||
| 457 | |||
| 458 | config WANPIPE_FR | ||
| 459 | bool "WANPIPE Frame Relay support" | ||
| 460 | depends on VENDOR_SANGOMA | ||
| 461 | help | ||
| 462 | Connect a WANPIPE card to a Frame Relay network, or use Frame Relay | ||
| 463 | API to develop custom applications. | ||
| 464 | |||
| 465 | Contains the Ethernet Bridging over Frame Relay feature, where | ||
| 466 | a WANPIPE frame relay link can be directly connected to the Linux | ||
| 467 | kernel bridge. The Frame Relay option is supported on S514-PCI | ||
| 468 | and S508-ISA cards. | ||
| 469 | |||
| 470 | Say Y and the Frame Relay support will be included in the driver. | ||
| 471 | |||
| 472 | config WANPIPE_X25 | ||
| 473 | bool "WANPIPE X.25 support" | ||
| 474 | depends on VENDOR_SANGOMA | ||
| 475 | help | ||
| 476 | Connect a WANPIPE card to an X.25 network. | ||
| 477 | |||
| 478 | Includes the X.25 API support for custom applications over the | ||
| 479 | X.25 protocol. The X.25 option is supported on S514-PCI and | ||
| 480 | S508-ISA cards. | ||
| 481 | |||
| 482 | Say Y and the X.25 support will be included in the driver. | ||
| 483 | |||
| 484 | config WANPIPE_PPP | ||
| 485 | bool "WANPIPE PPP support" | ||
| 486 | depends on VENDOR_SANGOMA | ||
| 487 | help | ||
| 488 | Connect a WANPIPE card to a leased line using Point-to-Point | ||
| 489 | Protocol (PPP). | ||
| 490 | |||
| 491 | The PPP option is supported on S514-PCI/S508-ISA cards. | ||
| 492 | |||
| 493 | Say Y and the PPP support will be included in the driver. | ||
| 494 | |||
| 495 | config WANPIPE_MULTPPP | ||
| 496 | bool "WANPIPE Multi-Port PPP support" | ||
| 497 | depends on VENDOR_SANGOMA | ||
| 498 | help | ||
| 499 | Connect a WANPIPE card to a leased line using Point-to-Point | ||
| 500 | Protocol (PPP). | ||
| 501 | |||
| 502 | Uses in-kernel SyncPPP protocol over the Sangoma HDLC Streaming | ||
| 503 | adapter. In this case each Sangoma adapter port can support an | ||
| 504 | independent PPP connection. For example, a single Quad-Port PCI | ||
| 505 | adapter can support up to four independent PPP links. The PPP | ||
| 506 | option is supported on S514-PCI/S508-ISA cards. | ||
| 507 | |||
| 508 | Say Y and the Multi-Port PPP support will be included in the driver. | ||
| 509 | |||
| 510 | config CYCLADES_SYNC | 413 | config CYCLADES_SYNC |
| 511 | tristate "Cyclom 2X(tm) cards (EXPERIMENTAL)" | 414 | tristate "Cyclom 2X(tm) cards (EXPERIMENTAL)" |
| 512 | depends on WAN_ROUTER_DRIVERS && (PCI || ISA) | 415 | depends on WAN_ROUTER_DRIVERS && (PCI || ISA) |
diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile index ce6c56b903e7..823c6d5ab90d 100644 --- a/drivers/net/wan/Makefile +++ b/drivers/net/wan/Makefile | |||
| @@ -5,14 +5,6 @@ | |||
| 5 | # Rewritten to use lists instead of if-statements. | 5 | # Rewritten to use lists instead of if-statements. |
| 6 | # | 6 | # |
| 7 | 7 | ||
| 8 | wanpipe-y := sdlamain.o sdla_ft1.o | ||
| 9 | wanpipe-$(CONFIG_WANPIPE_X25) += sdla_x25.o | ||
| 10 | wanpipe-$(CONFIG_WANPIPE_FR) += sdla_fr.o | ||
| 11 | wanpipe-$(CONFIG_WANPIPE_CHDLC) += sdla_chdlc.o | ||
| 12 | wanpipe-$(CONFIG_WANPIPE_PPP) += sdla_ppp.o | ||
| 13 | wanpipe-$(CONFIG_WANPIPE_MULTPPP) += wanpipe_multppp.o | ||
| 14 | wanpipe-objs := $(wanpipe-y) | ||
| 15 | |||
| 16 | cyclomx-y := cycx_main.o | 8 | cyclomx-y := cycx_main.o |
| 17 | cyclomx-$(CONFIG_CYCLOMX_X25) += cycx_x25.o | 9 | cyclomx-$(CONFIG_CYCLOMX_X25) += cycx_x25.o |
| 18 | cyclomx-objs := $(cyclomx-y) | 10 | cyclomx-objs := $(cyclomx-y) |
| @@ -43,11 +35,6 @@ obj-$(CONFIG_LANMEDIA) += lmc/ | |||
| 43 | 35 | ||
| 44 | obj-$(CONFIG_DLCI) += dlci.o | 36 | obj-$(CONFIG_DLCI) += dlci.o |
| 45 | obj-$(CONFIG_SDLA) += sdla.o | 37 | obj-$(CONFIG_SDLA) += sdla.o |
| 46 | ifeq ($(CONFIG_WANPIPE_MULTPPP),y) | ||
| 47 | obj-$(CONFIG_VENDOR_SANGOMA) += sdladrv.o wanpipe.o syncppp.o | ||
| 48 | else | ||
| 49 | obj-$(CONFIG_VENDOR_SANGOMA) += sdladrv.o wanpipe.o | ||
| 50 | endif | ||
| 51 | obj-$(CONFIG_CYCLADES_SYNC) += cycx_drv.o cyclomx.o | 38 | obj-$(CONFIG_CYCLADES_SYNC) += cycx_drv.o cyclomx.o |
| 52 | obj-$(CONFIG_LAPBETHER) += lapbether.o | 39 | obj-$(CONFIG_LAPBETHER) += lapbether.o |
| 53 | obj-$(CONFIG_SBNI) += sbni.o | 40 | obj-$(CONFIG_SBNI) += sbni.o |
diff --git a/drivers/net/wan/sdla_chdlc.c b/drivers/net/wan/sdla_chdlc.c deleted file mode 100644 index 496d29237e92..000000000000 --- a/drivers/net/wan/sdla_chdlc.c +++ /dev/null | |||
| @@ -1,4428 +0,0 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * sdla_chdlc.c WANPIPE(tm) Multiprotocol WAN Link Driver. Cisco HDLC module. | ||
| 3 | * | ||
| 4 | * Authors: Nenad Corbic <ncorbic@sangoma.com> | ||
| 5 | * Gideon Hack | ||
| 6 | * | ||
| 7 | * Copyright: (c) 1995-2001 Sangoma Technologies Inc. | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or | ||
| 10 | * modify it under the terms of the GNU General Public License | ||
| 11 | * as published by the Free Software Foundation; either version | ||
| 12 | * 2 of the License, or (at your option) any later version. | ||
| 13 | * ============================================================================ | ||
| 14 | * Feb 28, 2001 Nenad Corbic Updated if_tx_timeout() routine for | ||
| 15 | * 2.4.X kernels. | ||
| 16 | * Jan 25, 2001 Nenad Corbic Added a TTY Sync serial driver over the | ||
| 17 | * HDLC streaming protocol | ||
| 18 | * Added a TTY Async serial driver over the | ||
| 19 | * Async protocol. | ||
| 20 | * Dec 15, 2000 Nenad Corbic Updated for 2.4.X Kernel support | ||
| 21 | * Nov 13, 2000 Nenad Corbic Added true interface type encoding option. | ||
| 22 | * Tcpdump doesn't support CHDLC inteface | ||
| 23 | * types, to fix this "true type" option will set | ||
| 24 | * the interface type to RAW IP mode. | ||
| 25 | * Nov 07, 2000 Nenad Corbic Added security features for UDP debugging: | ||
| 26 | * Deny all and specify allowed requests. | ||
| 27 | * Jun 20, 2000 Nenad Corbic Fixed the API IP ERROR bug. Caused by the | ||
| 28 | * latest update. | ||
| 29 | * May 09, 2000 Nenad Corbic Option to bring down an interface | ||
| 30 | * upon disconnect. | ||
| 31 | * Mar 23, 2000 Nenad Corbic Improved task queue, bh handling. | ||
| 32 | * Mar 16, 2000 Nenad Corbic Fixed the SLARP Dynamic IP addressing. | ||
| 33 | * Mar 06, 2000 Nenad Corbic Bug Fix: corrupted mbox recovery. | ||
| 34 | * Feb 10, 2000 Gideon Hack Added ASYNC support. | ||
| 35 | * Feb 09, 2000 Nenad Corbic Fixed two shutdown bugs in update() and | ||
| 36 | * if_stats() functions. | ||
| 37 | * Jan 24, 2000 Nenad Corbic Fixed a startup wanpipe state racing, | ||
| 38 | * condition between if_open and isr. | ||
| 39 | * Jan 10, 2000 Nenad Corbic Added new socket API support. | ||
| 40 | * Dev 15, 1999 Nenad Corbic Fixed up header files for 2.0.X kernels | ||
| 41 | * Nov 20, 1999 Nenad Corbic Fixed zero length API bug. | ||
| 42 | * Sep 30, 1999 Nenad Corbic Fixed dynamic IP and route setup. | ||
| 43 | * Sep 23, 1999 Nenad Corbic Added SMP support, fixed tracing | ||
| 44 | * Sep 13, 1999 Nenad Corbic Split up Port 0 and 1 into separate devices. | ||
| 45 | * Jun 02, 1999 Gideon Hack Added support for the S514 adapter. | ||
| 46 | * Oct 30, 1998 Jaspreet Singh Added Support for CHDLC API (HDLC STREAMING). | ||
| 47 | * Oct 28, 1998 Jaspreet Singh Added Support for Dual Port CHDLC. | ||
| 48 | * Aug 07, 1998 David Fong Initial version. | ||
| 49 | *****************************************************************************/ | ||
| 50 | |||
| 51 | #include <linux/module.h> | ||
| 52 | #include <linux/kernel.h> /* printk(), and other useful stuff */ | ||
| 53 | #include <linux/stddef.h> /* offsetof(), etc. */ | ||
| 54 | #include <linux/errno.h> /* return codes */ | ||
| 55 | #include <linux/string.h> /* inline memset(), etc. */ | ||
| 56 | #include <linux/slab.h> /* kmalloc(), kfree() */ | ||
| 57 | #include <linux/wanrouter.h> /* WAN router definitions */ | ||
| 58 | #include <linux/wanpipe.h> /* WANPIPE common user API definitions */ | ||
| 59 | #include <linux/if_arp.h> /* ARPHRD_* defines */ | ||
| 60 | |||
| 61 | |||
| 62 | #include <asm/uaccess.h> | ||
| 63 | #include <linux/inetdevice.h> | ||
| 64 | #include <linux/netdevice.h> | ||
| 65 | |||
| 66 | #include <linux/in.h> /* sockaddr_in */ | ||
| 67 | #include <linux/inet.h> | ||
| 68 | #include <linux/if.h> | ||
| 69 | #include <asm/byteorder.h> /* htons(), etc. */ | ||
| 70 | #include <linux/sdlapci.h> | ||
| 71 | #include <asm/io.h> | ||
| 72 | |||
| 73 | #include <linux/sdla_chdlc.h> /* CHDLC firmware API definitions */ | ||
| 74 | #include <linux/sdla_asy.h> /* CHDLC (async) API definitions */ | ||
| 75 | |||
| 76 | #include <linux/if_wanpipe_common.h> /* Socket Driver common area */ | ||
| 77 | #include <linux/if_wanpipe.h> | ||
| 78 | |||
| 79 | /* TTY Includes */ | ||
| 80 | #include <linux/tty.h> | ||
| 81 | #include <linux/tty_flip.h> | ||
| 82 | #include <linux/serial.h> | ||
| 83 | |||
| 84 | |||
| 85 | /****** Defines & Macros ****************************************************/ | ||
| 86 | |||
| 87 | /* reasons for enabling the timer interrupt on the adapter */ | ||
| 88 | #define TMR_INT_ENABLED_UDP 0x01 | ||
| 89 | #define TMR_INT_ENABLED_UPDATE 0x02 | ||
| 90 | #define TMR_INT_ENABLED_CONFIG 0x10 | ||
| 91 | |||
| 92 | #define MAX_IP_ERRORS 10 | ||
| 93 | |||
| 94 | #define TTY_CHDLC_MAX_MTU 2000 | ||
| 95 | #define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ | ||
| 96 | #define CHDLC_HDR_LEN 1 | ||
| 97 | |||
| 98 | #define CHDLC_API 0x01 | ||
| 99 | |||
| 100 | #define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) | ||
| 101 | #define MAX_BH_BUFF 10 | ||
| 102 | |||
| 103 | //#define PRINT_DEBUG | ||
| 104 | #ifdef PRINT_DEBUG | ||
| 105 | #define dbg_printk(format, a...) printk(format, ## a) | ||
| 106 | #else | ||
| 107 | #define dbg_printk(format, a...) | ||
| 108 | #endif | ||
| 109 | |||
| 110 | /******Data Structures*****************************************************/ | ||
| 111 | |||
| 112 | /* This structure is placed in the private data area of the device structure. | ||
| 113 | * The card structure used to occupy the private area but now the following | ||
| 114 | * structure will incorporate the card structure along with CHDLC specific data | ||
| 115 | */ | ||
| 116 | |||
| 117 | typedef struct chdlc_private_area | ||
| 118 | { | ||
| 119 | wanpipe_common_t common; | ||
| 120 | sdla_t *card; | ||
| 121 | int TracingEnabled; /* For enabling Tracing */ | ||
| 122 | unsigned long curr_trace_addr; /* Used for Tracing */ | ||
| 123 | unsigned long start_trace_addr; | ||
| 124 | unsigned long end_trace_addr; | ||
| 125 | unsigned long base_addr_trace_buffer; | ||
| 126 | unsigned long end_addr_trace_buffer; | ||
| 127 | unsigned short number_trace_elements; | ||
| 128 | unsigned available_buffer_space; | ||
| 129 | unsigned long router_start_time; | ||
| 130 | unsigned char route_status; | ||
| 131 | unsigned char route_removed; | ||
| 132 | unsigned long tick_counter; /* For 5s timeout counter */ | ||
| 133 | unsigned long router_up_time; | ||
| 134 | u32 IP_address; /* IP addressing */ | ||
| 135 | u32 IP_netmask; | ||
| 136 | u32 ip_local; | ||
| 137 | u32 ip_remote; | ||
| 138 | u32 ip_local_tmp; | ||
| 139 | u32 ip_remote_tmp; | ||
| 140 | u8 ip_error; | ||
| 141 | u8 config_chdlc; | ||
| 142 | u8 config_chdlc_timeout; | ||
| 143 | unsigned char mc; /* Mulitcast support on/off */ | ||
| 144 | unsigned short udp_pkt_lgth; /* udp packet processing */ | ||
| 145 | char udp_pkt_src; | ||
| 146 | char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; | ||
| 147 | unsigned short timer_int_enabled; | ||
| 148 | char update_comms_stats; /* updating comms stats */ | ||
| 149 | |||
| 150 | bh_data_t *bh_head; /* Circular buffer for chdlc_bh */ | ||
| 151 | unsigned long tq_working; | ||
| 152 | volatile int bh_write; | ||
| 153 | volatile int bh_read; | ||
| 154 | atomic_t bh_buff_used; | ||
| 155 | |||
| 156 | unsigned char interface_down; | ||
| 157 | |||
| 158 | /* Polling work queue entry. Each interface | ||
| 159 | * has its own work queue entry, which is used | ||
| 160 | * to defer events from the interrupt */ | ||
| 161 | struct work_struct poll_work; | ||
| 162 | struct timer_list poll_delay_timer; | ||
| 163 | |||
| 164 | u8 gateway; | ||
| 165 | u8 true_if_encoding; | ||
| 166 | //FIXME: add driver stats as per frame relay! | ||
| 167 | |||
| 168 | } chdlc_private_area_t; | ||
| 169 | |||
| 170 | /* Route Status options */ | ||
| 171 | #define NO_ROUTE 0x00 | ||
| 172 | #define ADD_ROUTE 0x01 | ||
| 173 | #define ROUTE_ADDED 0x02 | ||
| 174 | #define REMOVE_ROUTE 0x03 | ||
| 175 | |||
| 176 | |||
| 177 | /* variable for keeping track of enabling/disabling FT1 monitor status */ | ||
| 178 | static int rCount = 0; | ||
| 179 | |||
| 180 | /* variable for tracking how many interfaces to open for WANPIPE on the | ||
| 181 | two ports */ | ||
| 182 | |||
| 183 | extern void disable_irq(unsigned int); | ||
| 184 | extern void enable_irq(unsigned int); | ||
| 185 | |||
| 186 | /****** Function Prototypes *************************************************/ | ||
| 187 | /* WAN link driver entry points. These are called by the WAN router module. */ | ||
| 188 | static int update(struct wan_device* wandev); | ||
| 189 | static int new_if(struct wan_device* wandev, struct net_device* dev, | ||
| 190 | wanif_conf_t* conf); | ||
| 191 | |||
| 192 | /* Network device interface */ | ||
| 193 | static int if_init(struct net_device* dev); | ||
| 194 | static int if_open(struct net_device* dev); | ||
| 195 | static int if_close(struct net_device* dev); | ||
| 196 | static int if_header(struct sk_buff* skb, struct net_device* dev, | ||
| 197 | unsigned short type, void* daddr, void* saddr, | ||
| 198 | unsigned len); | ||
| 199 | |||
| 200 | static int if_rebuild_hdr (struct sk_buff *skb); | ||
| 201 | static struct net_device_stats* if_stats(struct net_device* dev); | ||
| 202 | |||
| 203 | static int if_send(struct sk_buff* skb, struct net_device* dev); | ||
| 204 | |||
| 205 | /* CHDLC Firmware interface functions */ | ||
| 206 | static int chdlc_configure (sdla_t* card, void* data); | ||
| 207 | static int chdlc_comm_enable (sdla_t* card); | ||
| 208 | static int chdlc_read_version (sdla_t* card, char* str); | ||
| 209 | static int chdlc_set_intr_mode (sdla_t* card, unsigned mode); | ||
| 210 | static int chdlc_send (sdla_t* card, void* data, unsigned len); | ||
| 211 | static int chdlc_read_comm_err_stats (sdla_t* card); | ||
| 212 | static int chdlc_read_op_stats (sdla_t* card); | ||
| 213 | static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb); | ||
| 214 | |||
| 215 | |||
| 216 | static int chdlc_disable_comm_shutdown (sdla_t *card); | ||
| 217 | static void if_tx_timeout(struct net_device *dev); | ||
| 218 | |||
| 219 | /* Miscellaneous CHDLC Functions */ | ||
| 220 | static int set_chdlc_config (sdla_t* card); | ||
| 221 | static void init_chdlc_tx_rx_buff( sdla_t* card); | ||
| 222 | static int process_chdlc_exception(sdla_t *card); | ||
| 223 | static int process_global_exception(sdla_t *card); | ||
| 224 | static int update_comms_stats(sdla_t* card, | ||
| 225 | chdlc_private_area_t* chdlc_priv_area); | ||
| 226 | static int configure_ip (sdla_t* card); | ||
| 227 | static int unconfigure_ip (sdla_t* card); | ||
| 228 | static void process_route(sdla_t *card); | ||
| 229 | static void port_set_state (sdla_t *card, int); | ||
| 230 | static int config_chdlc (sdla_t *card); | ||
| 231 | static void disable_comm (sdla_t *card); | ||
| 232 | |||
| 233 | static void trigger_chdlc_poll(struct net_device *dev); | ||
| 234 | static void chdlc_poll(struct net_device *dev); | ||
| 235 | static void chdlc_poll_delay (unsigned long dev_ptr); | ||
| 236 | |||
| 237 | |||
| 238 | /* Miscellaneous asynchronous interface Functions */ | ||
| 239 | static int set_asy_config (sdla_t* card); | ||
| 240 | static int asy_comm_enable (sdla_t* card); | ||
| 241 | |||
| 242 | /* Interrupt handlers */ | ||
| 243 | static void wpc_isr (sdla_t* card); | ||
| 244 | static void rx_intr (sdla_t* card); | ||
| 245 | static void timer_intr(sdla_t *); | ||
| 246 | |||
| 247 | /* Bottom half handlers */ | ||
| 248 | static void chdlc_work(struct net_device *dev); | ||
| 249 | static int chdlc_work_cleanup(struct net_device *dev); | ||
| 250 | static int bh_enqueue(struct net_device *dev, struct sk_buff *skb); | ||
| 251 | |||
| 252 | /* Miscellaneous functions */ | ||
| 253 | static int chk_bcast_mcast_addr(sdla_t* card, struct net_device* dev, | ||
| 254 | struct sk_buff *skb); | ||
| 255 | static int reply_udp( unsigned char *data, unsigned int mbox_len ); | ||
| 256 | static int intr_test( sdla_t* card); | ||
| 257 | static int udp_pkt_type( struct sk_buff *skb , sdla_t* card); | ||
| 258 | static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, | ||
| 259 | struct sk_buff *skb, struct net_device* dev, | ||
| 260 | chdlc_private_area_t* chdlc_priv_area); | ||
| 261 | static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, | ||
| 262 | chdlc_private_area_t* chdlc_priv_area); | ||
| 263 | static unsigned short calc_checksum (char *, int); | ||
| 264 | static void s508_lock (sdla_t *card, unsigned long *smp_flags); | ||
| 265 | static void s508_unlock (sdla_t *card, unsigned long *smp_flags); | ||
| 266 | |||
| 267 | |||
| 268 | static int Intr_test_counter; | ||
| 269 | |||
| 270 | /* TTY Global Definitions */ | ||
| 271 | |||
| 272 | #define NR_PORTS 4 | ||
| 273 | #define WAN_TTY_MAJOR 226 | ||
| 274 | #define WAN_TTY_MINOR 0 | ||
| 275 | |||
| 276 | #define WAN_CARD(port) (tty_card_map[port]) | ||
| 277 | #define MIN_PORT 0 | ||
| 278 | #define MAX_PORT NR_PORTS-1 | ||
| 279 | |||
| 280 | #define CRC_LENGTH 2 | ||
| 281 | |||
| 282 | static int wanpipe_tty_init(sdla_t *card); | ||
| 283 | static void wanpipe_tty_receive(sdla_t *, unsigned, unsigned int); | ||
| 284 | static void wanpipe_tty_trigger_poll(sdla_t *card); | ||
| 285 | |||
| 286 | static struct tty_driver serial_driver; | ||
| 287 | static int tty_init_cnt=0; | ||
| 288 | |||
| 289 | static struct serial_state rs_table[NR_PORTS]; | ||
| 290 | |||
| 291 | static char tty_driver_mode=WANOPT_TTY_SYNC; | ||
| 292 | |||
| 293 | static char *opt_decode[] = {"NONE","CRTSCTS","XONXOFF-RX", | ||
| 294 | "CRTSCTS XONXOFF-RX","XONXOFF-TX", | ||
| 295 | "CRTSCTS XONXOFF-TX","CRTSCTS XONXOFF"}; | ||
| 296 | static char *p_decode[] = {"NONE","ODD","EVEN"}; | ||
| 297 | |||
| 298 | static void* tty_card_map[NR_PORTS] = {NULL,NULL,NULL,NULL}; | ||
| 299 | |||
| 300 | |||
| 301 | /****** Public Functions ****************************************************/ | ||
| 302 | |||
| 303 | /*============================================================================ | ||
| 304 | * Cisco HDLC protocol initialization routine. | ||
| 305 | * | ||
| 306 | * This routine is called by the main WANPIPE module during setup. At this | ||
| 307 | * point adapter is completely initialized and firmware is running. | ||
| 308 | * o read firmware version (to make sure it's alive) | ||
| 309 | * o configure adapter | ||
| 310 | * o initialize protocol-specific fields of the adapter data space. | ||
| 311 | * | ||
| 312 | * Return: 0 o.k. | ||
| 313 | * < 0 failure. | ||
| 314 | */ | ||
| 315 | int wpc_init (sdla_t* card, wandev_conf_t* conf) | ||
| 316 | { | ||
| 317 | unsigned char port_num; | ||
| 318 | int err; | ||
| 319 | unsigned long max_permitted_baud = 0; | ||
| 320 | SHARED_MEMORY_INFO_STRUCT *flags; | ||
| 321 | |||
| 322 | union | ||
| 323 | { | ||
| 324 | char str[80]; | ||
| 325 | } u; | ||
| 326 | volatile CHDLC_MAILBOX_STRUCT* mb; | ||
| 327 | CHDLC_MAILBOX_STRUCT* mb1; | ||
| 328 | unsigned long timeout; | ||
| 329 | |||
| 330 | /* Verify configuration ID */ | ||
| 331 | if (conf->config_id != WANCONFIG_CHDLC) { | ||
| 332 | printk(KERN_INFO "%s: invalid configuration ID %u!\n", | ||
| 333 | card->devname, conf->config_id); | ||
| 334 | return -EINVAL; | ||
| 335 | } | ||
| 336 | |||
| 337 | /* Find out which Port to use */ | ||
| 338 | if ((conf->comm_port == WANOPT_PRI) || (conf->comm_port == WANOPT_SEC)){ | ||
| 339 | if (card->next){ | ||
| 340 | |||
| 341 | if (conf->comm_port != card->next->u.c.comm_port){ | ||
| 342 | card->u.c.comm_port = conf->comm_port; | ||
| 343 | }else{ | ||
| 344 | printk(KERN_INFO "%s: ERROR - %s port used!\n", | ||
| 345 | card->wandev.name, PORT(conf->comm_port)); | ||
| 346 | return -EINVAL; | ||
| 347 | } | ||
| 348 | }else{ | ||
| 349 | card->u.c.comm_port = conf->comm_port; | ||
| 350 | } | ||
| 351 | }else{ | ||
| 352 | printk(KERN_INFO "%s: ERROR - Invalid Port Selected!\n", | ||
| 353 | card->wandev.name); | ||
| 354 | return -EINVAL; | ||
| 355 | } | ||
| 356 | |||
| 357 | |||
| 358 | /* Initialize protocol-specific fields */ | ||
| 359 | if(card->hw.type != SDLA_S514){ | ||
| 360 | |||
| 361 | if (card->u.c.comm_port == WANOPT_PRI){ | ||
| 362 | card->mbox = (void *) card->hw.dpmbase; | ||
| 363 | }else{ | ||
| 364 | card->mbox = (void *) card->hw.dpmbase + | ||
| 365 | SEC_BASE_ADDR_MB_STRUCT - PRI_BASE_ADDR_MB_STRUCT; | ||
| 366 | } | ||
| 367 | }else{ | ||
| 368 | /* for a S514 adapter, set a pointer to the actual mailbox in the */ | ||
| 369 | /* allocated virtual memory area */ | ||
| 370 | if (card->u.c.comm_port == WANOPT_PRI){ | ||
| 371 | card->mbox = (void *) card->hw.dpmbase + PRI_BASE_ADDR_MB_STRUCT; | ||
| 372 | }else{ | ||
| 373 | card->mbox = (void *) card->hw.dpmbase + SEC_BASE_ADDR_MB_STRUCT; | ||
| 374 | } | ||
| 375 | } | ||
| 376 | |||
| 377 | mb = mb1 = card->mbox; | ||
| 378 | |||
| 379 | if (!card->configured){ | ||
| 380 | |||
| 381 | /* The board will place an 'I' in the return code to indicate that it is | ||
| 382 | ready to accept commands. We expect this to be completed in less | ||
| 383 | than 1 second. */ | ||
| 384 | |||
| 385 | timeout = jiffies; | ||
| 386 | while (mb->return_code != 'I') /* Wait 1s for board to initialize */ | ||
| 387 | if ((jiffies - timeout) > 1*HZ) break; | ||
| 388 | |||
| 389 | if (mb->return_code != 'I') { | ||
| 390 | printk(KERN_INFO | ||
| 391 | "%s: Initialization not completed by adapter\n", | ||
| 392 | card->devname); | ||
| 393 | printk(KERN_INFO "Please contact Sangoma representative.\n"); | ||
| 394 | return -EIO; | ||
| 395 | } | ||
| 396 | } | ||
| 397 | |||
| 398 | /* Read firmware version. Note that when adapter initializes, it | ||
| 399 | * clears the mailbox, so it may appear that the first command was | ||
| 400 | * executed successfully when in fact it was merely erased. To work | ||
| 401 | * around this, we execute the first command twice. | ||
| 402 | */ | ||
| 403 | |||
| 404 | if (chdlc_read_version(card, u.str)) | ||
| 405 | return -EIO; | ||
| 406 | |||
| 407 | printk(KERN_INFO "%s: Running Cisco HDLC firmware v%s\n", | ||
| 408 | card->devname, u.str); | ||
| 409 | |||
| 410 | card->isr = &wpc_isr; | ||
| 411 | card->poll = NULL; | ||
| 412 | card->exec = NULL; | ||
| 413 | card->wandev.update = &update; | ||
| 414 | card->wandev.new_if = &new_if; | ||
| 415 | card->wandev.del_if = NULL; | ||
| 416 | card->wandev.udp_port = conf->udp_port; | ||
| 417 | card->disable_comm = &disable_comm; | ||
| 418 | card->wandev.new_if_cnt = 0; | ||
| 419 | |||
| 420 | /* reset the number of times the 'update()' proc has been called */ | ||
| 421 | card->u.c.update_call_count = 0; | ||
| 422 | |||
| 423 | card->wandev.ttl = conf->ttl; | ||
| 424 | card->wandev.interface = conf->interface; | ||
| 425 | |||
| 426 | if ((card->u.c.comm_port == WANOPT_SEC && conf->interface == WANOPT_V35)&& | ||
| 427 | card->hw.type != SDLA_S514){ | ||
| 428 | printk(KERN_INFO "%s: ERROR - V35 Interface not supported on S508 %s port \n", | ||
| 429 | card->devname, PORT(card->u.c.comm_port)); | ||
| 430 | return -EIO; | ||
| 431 | } | ||
| 432 | |||
| 433 | card->wandev.clocking = conf->clocking; | ||
| 434 | |||
| 435 | port_num = card->u.c.comm_port; | ||
| 436 | |||
| 437 | /* in API mode, we can configure for "receive only" buffering */ | ||
| 438 | if(card->hw.type == SDLA_S514) { | ||
| 439 | card->u.c.receive_only = conf->receive_only; | ||
| 440 | if(conf->receive_only) { | ||
| 441 | printk(KERN_INFO | ||
| 442 | "%s: Configured for 'receive only' mode\n", | ||
| 443 | card->devname); | ||
| 444 | } | ||
| 445 | } | ||
| 446 | |||
| 447 | /* Setup Port Bps */ | ||
| 448 | |||
| 449 | if(card->wandev.clocking) { | ||
| 450 | if((port_num == WANOPT_PRI) || card->u.c.receive_only) { | ||
| 451 | /* For Primary Port 0 */ | ||
| 452 | max_permitted_baud = | ||
| 453 | (card->hw.type == SDLA_S514) ? | ||
| 454 | PRI_MAX_BAUD_RATE_S514 : | ||
| 455 | PRI_MAX_BAUD_RATE_S508; | ||
| 456 | |||
| 457 | }else if(port_num == WANOPT_SEC) { | ||
| 458 | /* For Secondary Port 1 */ | ||
| 459 | max_permitted_baud = | ||
| 460 | (card->hw.type == SDLA_S514) ? | ||
| 461 | SEC_MAX_BAUD_RATE_S514 : | ||
| 462 | SEC_MAX_BAUD_RATE_S508; | ||
| 463 | } | ||
| 464 | |||
| 465 | if(conf->bps > max_permitted_baud) { | ||
| 466 | conf->bps = max_permitted_baud; | ||
| 467 | printk(KERN_INFO "%s: Baud too high!\n", | ||
| 468 | card->wandev.name); | ||
| 469 | printk(KERN_INFO "%s: Baud rate set to %lu bps\n", | ||
| 470 | card->wandev.name, max_permitted_baud); | ||
| 471 | } | ||
| 472 | card->wandev.bps = conf->bps; | ||
| 473 | }else{ | ||
| 474 | card->wandev.bps = 0; | ||
| 475 | } | ||
| 476 | |||
| 477 | /* Setup the Port MTU */ | ||
| 478 | if((port_num == WANOPT_PRI) || card->u.c.receive_only) { | ||
| 479 | |||
| 480 | /* For Primary Port 0 */ | ||
| 481 | card->wandev.mtu = | ||
| 482 | (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? | ||
| 483 | min_t(unsigned int, conf->mtu, PRI_MAX_NO_DATA_BYTES_IN_FRAME) : | ||
| 484 | CHDLC_DFLT_DATA_LEN; | ||
| 485 | } else if(port_num == WANOPT_SEC) { | ||
| 486 | /* For Secondary Port 1 */ | ||
| 487 | card->wandev.mtu = | ||
| 488 | (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? | ||
| 489 | min_t(unsigned int, conf->mtu, SEC_MAX_NO_DATA_BYTES_IN_FRAME) : | ||
| 490 | CHDLC_DFLT_DATA_LEN; | ||
| 491 | } | ||
| 492 | |||
| 493 | /* Set up the interrupt status area */ | ||
| 494 | /* Read the CHDLC Configuration and obtain: | ||
| 495 | * Ptr to shared memory infor struct | ||
| 496 | * Use this pointer to calculate the value of card->u.c.flags ! | ||
| 497 | */ | ||
| 498 | mb1->buffer_length = 0; | ||
| 499 | mb1->command = READ_CHDLC_CONFIGURATION; | ||
| 500 | err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT; | ||
| 501 | if(err != COMMAND_OK) { | ||
| 502 | if(card->hw.type != SDLA_S514) | ||
| 503 | enable_irq(card->hw.irq); | ||
| 504 | |||
| 505 | chdlc_error(card, err, mb1); | ||
| 506 | return -EIO; | ||
| 507 | } | ||
| 508 | |||
| 509 | if(card->hw.type == SDLA_S514){ | ||
| 510 | card->u.c.flags = (void *)(card->hw.dpmbase + | ||
| 511 | (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> | ||
| 512 | ptr_shared_mem_info_struct)); | ||
| 513 | }else{ | ||
| 514 | card->u.c.flags = (void *)(card->hw.dpmbase + | ||
| 515 | (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> | ||
| 516 | ptr_shared_mem_info_struct % SDLA_WINDOWSIZE)); | ||
| 517 | } | ||
| 518 | |||
| 519 | flags = card->u.c.flags; | ||
| 520 | |||
| 521 | /* This is for the ports link state */ | ||
| 522 | card->wandev.state = WAN_DUALPORT; | ||
| 523 | card->u.c.state = WAN_DISCONNECTED; | ||
| 524 | |||
| 525 | |||
| 526 | if (!card->wandev.piggyback){ | ||
| 527 | int err; | ||
| 528 | |||
| 529 | /* Perform interrupt testing */ | ||
| 530 | err = intr_test(card); | ||
| 531 | |||
| 532 | if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { | ||
| 533 | printk(KERN_INFO "%s: Interrupt test failed (%i)\n", | ||
| 534 | card->devname, Intr_test_counter); | ||
| 535 | printk(KERN_INFO "%s: Please choose another interrupt\n", | ||
| 536 | card->devname); | ||
| 537 | return -EIO; | ||
| 538 | } | ||
| 539 | |||
| 540 | printk(KERN_INFO "%s: Interrupt test passed (%i)\n", | ||
| 541 | card->devname, Intr_test_counter); | ||
| 542 | card->configured = 1; | ||
| 543 | } | ||
| 544 | |||
| 545 | if ((card->tty_opt=conf->tty) == WANOPT_YES){ | ||
| 546 | int err; | ||
| 547 | card->tty_minor = conf->tty_minor; | ||
| 548 | |||
| 549 | /* On ASYNC connections internal clocking | ||
| 550 | * is mandatory */ | ||
| 551 | if ((card->u.c.async_mode = conf->tty_mode)){ | ||
| 552 | card->wandev.clocking = 1; | ||
| 553 | } | ||
| 554 | err=wanpipe_tty_init(card); | ||
| 555 | if (err){ | ||
| 556 | return err; | ||
| 557 | } | ||
| 558 | }else{ | ||
| 559 | |||
| 560 | |||
| 561 | if (chdlc_set_intr_mode(card, APP_INT_ON_TIMER)){ | ||
| 562 | printk (KERN_INFO "%s: " | ||
| 563 | "Failed to set interrupt triggers!\n", | ||
| 564 | card->devname); | ||
| 565 | return -EIO; | ||
| 566 | } | ||
| 567 | |||
| 568 | /* Mask the Timer interrupt */ | ||
| 569 | flags->interrupt_info_struct.interrupt_permission &= | ||
| 570 | ~APP_INT_ON_TIMER; | ||
| 571 | } | ||
| 572 | |||
| 573 | /* If we are using CHDLC in backup mode, this flag will | ||
| 574 | * indicate not to look for IP addresses in config_chdlc()*/ | ||
| 575 | card->u.c.backup = conf->backup; | ||
| 576 | |||
| 577 | printk(KERN_INFO "\n"); | ||
| 578 | |||
| 579 | return 0; | ||
| 580 | } | ||
| 581 | |||
| 582 | /******* WAN Device Driver Entry Points *************************************/ | ||
| 583 | |||
| 584 | /*============================================================================ | ||
| 585 | * Update device status & statistics | ||
| 586 | * This procedure is called when updating the PROC file system and returns | ||
| 587 | * various communications statistics. These statistics are accumulated from 3 | ||
| 588 | * different locations: | ||
| 589 | * 1) The 'if_stats' recorded for the device. | ||
| 590 | * 2) Communication error statistics on the adapter. | ||
| 591 | * 3) CHDLC operational statistics on the adapter. | ||
| 592 | * The board level statistics are read during a timer interrupt. Note that we | ||
| 593 | * read the error and operational statistics during consecitive timer ticks so | ||
| 594 | * as to minimize the time that we are inside the interrupt handler. | ||
| 595 | * | ||
| 596 | */ | ||
| 597 | static int update(struct wan_device* wandev) | ||
| 598 | { | ||
| 599 | sdla_t* card = wandev->private; | ||
| 600 | struct net_device* dev; | ||
| 601 | volatile chdlc_private_area_t* chdlc_priv_area; | ||
| 602 | SHARED_MEMORY_INFO_STRUCT *flags; | ||
| 603 | unsigned long timeout; | ||
| 604 | |||
| 605 | /* sanity checks */ | ||
| 606 | if((wandev == NULL) || (wandev->private == NULL)) | ||
| 607 | return -EFAULT; | ||
| 608 | |||
| 609 | if(wandev->state == WAN_UNCONFIGURED) | ||
| 610 | return -ENODEV; | ||
| 611 | |||
| 612 | /* more sanity checks */ | ||
| 613 | if(!card->u.c.flags) | ||
| 614 | return -ENODEV; | ||
| 615 | |||
| 616 | if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) | ||
| 617 | return -EAGAIN; | ||
| 618 | |||
| 619 | if((dev=card->wandev.dev) == NULL) | ||
| 620 | return -ENODEV; | ||
| 621 | |||
| 622 | if((chdlc_priv_area=dev->priv) == NULL) | ||
| 623 | return -ENODEV; | ||
| 624 | |||
| 625 | flags = card->u.c.flags; | ||
| 626 | if(chdlc_priv_area->update_comms_stats){ | ||
| 627 | return -EAGAIN; | ||
| 628 | } | ||
| 629 | |||
| 630 | /* we will need 2 timer interrupts to complete the */ | ||
| 631 | /* reading of the statistics */ | ||
| 632 | chdlc_priv_area->update_comms_stats = 2; | ||
| 633 | flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; | ||
| 634 | chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UPDATE; | ||
| 635 | |||
| 636 | /* wait a maximum of 1 second for the statistics to be updated */ | ||
| 637 | timeout = jiffies; | ||
| 638 | for(;;) { | ||
| 639 | if(chdlc_priv_area->update_comms_stats == 0) | ||
| 640 | break; | ||
| 641 | if ((jiffies - timeout) > (1 * HZ)){ | ||
| 642 | chdlc_priv_area->update_comms_stats = 0; | ||
| 643 | chdlc_priv_area->timer_int_enabled &= | ||
| 644 | ~TMR_INT_ENABLED_UPDATE; | ||
| 645 | return -EAGAIN; | ||
| 646 | } | ||
| 647 | } | ||
| 648 | |||
| 649 | return 0; | ||
| 650 | } | ||
| 651 | |||
| 652 | |||
| 653 | /*============================================================================ | ||
| 654 | * Create new logical channel. | ||
| 655 | * This routine is called by the router when ROUTER_IFNEW IOCTL is being | ||
| 656 | * handled. | ||
| 657 | * o parse media- and hardware-specific configuration | ||
| 658 | * o make sure that a new channel can be created | ||
| 659 | * o allocate resources, if necessary | ||
| 660 | * o prepare network device structure for registaration. | ||
| 661 | * | ||
| 662 | * Return: 0 o.k. | ||
| 663 | * < 0 failure (channel will not be created) | ||
| 664 | */ | ||
| 665 | static int new_if(struct wan_device* wandev, struct net_device* dev, | ||
| 666 | wanif_conf_t* conf) | ||
| 667 | { | ||
| 668 | sdla_t* card = wandev->private; | ||
| 669 | chdlc_private_area_t* chdlc_priv_area; | ||
| 670 | |||
| 671 | |||
| 672 | printk(KERN_INFO "%s: Configuring Interface: %s\n", | ||
| 673 | card->devname, conf->name); | ||
| 674 | |||
| 675 | if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { | ||
| 676 | printk(KERN_INFO "%s: Invalid interface name!\n", | ||
| 677 | card->devname); | ||
| 678 | return -EINVAL; | ||
| 679 | } | ||
| 680 | |||
| 681 | /* allocate and initialize private data */ | ||
| 682 | chdlc_priv_area = kmalloc(sizeof(chdlc_private_area_t), GFP_KERNEL); | ||
| 683 | |||
| 684 | if(chdlc_priv_area == NULL) | ||
| 685 | return -ENOMEM; | ||
| 686 | |||
| 687 | memset(chdlc_priv_area, 0, sizeof(chdlc_private_area_t)); | ||
| 688 | |||
| 689 | chdlc_priv_area->card = card; | ||
| 690 | chdlc_priv_area->common.sk = NULL; | ||
| 691 | chdlc_priv_area->common.func = NULL; | ||
| 692 | |||
| 693 | /* initialize data */ | ||
| 694 | strcpy(card->u.c.if_name, conf->name); | ||
| 695 | |||
| 696 | if(card->wandev.new_if_cnt > 0) { | ||
| 697 | kfree(chdlc_priv_area); | ||
| 698 | return -EEXIST; | ||
| 699 | } | ||
| 700 | |||
| 701 | card->wandev.new_if_cnt++; | ||
| 702 | |||
| 703 | chdlc_priv_area->TracingEnabled = 0; | ||
| 704 | chdlc_priv_area->route_status = NO_ROUTE; | ||
| 705 | chdlc_priv_area->route_removed = 0; | ||
| 706 | |||
| 707 | card->u.c.async_mode = conf->async_mode; | ||
| 708 | |||
| 709 | /* setup for asynchronous mode */ | ||
| 710 | if(conf->async_mode) { | ||
| 711 | printk(KERN_INFO "%s: Configuring for asynchronous mode\n", | ||
| 712 | wandev->name); | ||
| 713 | |||
| 714 | if(card->u.c.comm_port == WANOPT_PRI) { | ||
| 715 | printk(KERN_INFO | ||
| 716 | "%s:Asynchronous mode on secondary port only\n", | ||
| 717 | wandev->name); | ||
| 718 | kfree(chdlc_priv_area); | ||
| 719 | return -EINVAL; | ||
| 720 | } | ||
| 721 | |||
| 722 | if(strcmp(conf->usedby, "WANPIPE") == 0) { | ||
| 723 | printk(KERN_INFO | ||
| 724 | "%s: Running in WANIPE Async Mode\n", wandev->name); | ||
| 725 | card->u.c.usedby = WANPIPE; | ||
| 726 | }else{ | ||
| 727 | card->u.c.usedby = API; | ||
| 728 | } | ||
| 729 | |||
| 730 | if(!card->wandev.clocking) { | ||
| 731 | printk(KERN_INFO | ||
| 732 | "%s: Asynch. clocking must be 'Internal'\n", | ||
| 733 | wandev->name); | ||
| 734 | kfree(chdlc_priv_area); | ||
| 735 | return -EINVAL; | ||
| 736 | } | ||
| 737 | |||
| 738 | if((card->wandev.bps < MIN_ASY_BAUD_RATE) || | ||
| 739 | (card->wandev.bps > MAX_ASY_BAUD_RATE)) { | ||
| 740 | printk(KERN_INFO "%s: Selected baud rate is invalid.\n", | ||
| 741 | wandev->name); | ||
| 742 | printk(KERN_INFO "Must be between %u and %u bps.\n", | ||
| 743 | MIN_ASY_BAUD_RATE, MAX_ASY_BAUD_RATE); | ||
| 744 | kfree(chdlc_priv_area); | ||
| 745 | return -EINVAL; | ||
| 746 | } | ||
| 747 | |||
| 748 | card->u.c.api_options = 0; | ||
| 749 | if (conf->asy_data_trans == WANOPT_YES) { | ||
| 750 | card->u.c.api_options |= ASY_RX_DATA_TRANSPARENT; | ||
| 751 | } | ||
| 752 | |||
| 753 | card->u.c.protocol_options = 0; | ||
| 754 | if (conf->rts_hs_for_receive == WANOPT_YES) { | ||
| 755 | card->u.c.protocol_options |= ASY_RTS_HS_FOR_RX; | ||
| 756 | } | ||
| 757 | if (conf->xon_xoff_hs_for_receive == WANOPT_YES) { | ||
| 758 | card->u.c.protocol_options |= ASY_XON_XOFF_HS_FOR_RX; | ||
| 759 | } | ||
| 760 | if (conf->xon_xoff_hs_for_transmit == WANOPT_YES) { | ||
| 761 | card->u.c.protocol_options |= ASY_XON_XOFF_HS_FOR_TX; | ||
| 762 | } | ||
| 763 | if (conf->dcd_hs_for_transmit == WANOPT_YES) { | ||
| 764 | card->u.c.protocol_options |= ASY_DCD_HS_FOR_TX; | ||
| 765 | } | ||
| 766 | if (conf->cts_hs_for_transmit == WANOPT_YES) { | ||
| 767 | card->u.c.protocol_options |= ASY_CTS_HS_FOR_TX; | ||
| 768 | } | ||
| 769 | |||
| 770 | card->u.c.tx_bits_per_char = conf->tx_bits_per_char; | ||
| 771 | card->u.c.rx_bits_per_char = conf->rx_bits_per_char; | ||
| 772 | card->u.c.stop_bits = conf->stop_bits; | ||
| 773 | card->u.c.parity = conf->parity; | ||
| 774 | card->u.c.break_timer = conf->break_timer; | ||
| 775 | card->u.c.inter_char_timer = conf->inter_char_timer; | ||
| 776 | card->u.c.rx_complete_length = conf->rx_complete_length; | ||
| 777 | card->u.c.xon_char = conf->xon_char; | ||
| 778 | |||
| 779 | } else { /* setup for synchronous mode */ | ||
| 780 | |||
| 781 | card->u.c.protocol_options = 0; | ||
| 782 | if (conf->ignore_dcd == WANOPT_YES){ | ||
| 783 | card->u.c.protocol_options |= IGNORE_DCD_FOR_LINK_STAT; | ||
| 784 | } | ||
| 785 | if (conf->ignore_cts == WANOPT_YES){ | ||
| 786 | card->u.c.protocol_options |= IGNORE_CTS_FOR_LINK_STAT; | ||
| 787 | } | ||
| 788 | |||
| 789 | if (conf->ignore_keepalive == WANOPT_YES) { | ||
| 790 | card->u.c.protocol_options |= | ||
| 791 | IGNORE_KPALV_FOR_LINK_STAT; | ||
| 792 | card->u.c.kpalv_tx = MIN_Tx_KPALV_TIMER; | ||
| 793 | card->u.c.kpalv_rx = MIN_Rx_KPALV_TIMER; | ||
| 794 | card->u.c.kpalv_err = MIN_KPALV_ERR_TOL; | ||
| 795 | |||
| 796 | } else { /* Do not ignore keepalives */ | ||
| 797 | card->u.c.kpalv_tx = | ||
| 798 | ((conf->keepalive_tx_tmr - MIN_Tx_KPALV_TIMER) | ||
| 799 | >= 0) ? | ||
| 800 | min_t(unsigned int, conf->keepalive_tx_tmr,MAX_Tx_KPALV_TIMER) : | ||
| 801 | DEFAULT_Tx_KPALV_TIMER; | ||
| 802 | |||
| 803 | card->u.c.kpalv_rx = | ||
| 804 | ((conf->keepalive_rx_tmr - MIN_Rx_KPALV_TIMER) | ||
| 805 | >= 0) ? | ||
| 806 | min_t(unsigned int, conf->keepalive_rx_tmr,MAX_Rx_KPALV_TIMER) : | ||
| 807 | DEFAULT_Rx_KPALV_TIMER; | ||
| 808 | |||
| 809 | card->u.c.kpalv_err = | ||
| 810 | ((conf->keepalive_err_margin-MIN_KPALV_ERR_TOL) | ||
| 811 | >= 0) ? | ||
| 812 | min_t(unsigned int, conf->keepalive_err_margin, | ||
| 813 | MAX_KPALV_ERR_TOL) : | ||
| 814 | DEFAULT_KPALV_ERR_TOL; | ||
| 815 | } | ||
| 816 | |||
| 817 | /* Setup slarp timer to control delay between slarps */ | ||
| 818 | card->u.c.slarp_timer = | ||
| 819 | ((conf->slarp_timer - MIN_SLARP_REQ_TIMER) >= 0) ? | ||
| 820 | min_t(unsigned int, conf->slarp_timer, MAX_SLARP_REQ_TIMER) : | ||
| 821 | DEFAULT_SLARP_REQ_TIMER; | ||
| 822 | |||
| 823 | if (conf->hdlc_streaming == WANOPT_YES) { | ||
| 824 | printk(KERN_INFO "%s: Enabling HDLC STREAMING Mode\n", | ||
| 825 | wandev->name); | ||
| 826 | card->u.c.protocol_options = HDLC_STREAMING_MODE; | ||
| 827 | } | ||
| 828 | |||
| 829 | if ((chdlc_priv_area->true_if_encoding = conf->true_if_encoding) == WANOPT_YES){ | ||
| 830 | printk(KERN_INFO | ||
| 831 | "%s: Enabling, true interface type encoding.\n", | ||
| 832 | card->devname); | ||
| 833 | } | ||
| 834 | |||
| 835 | /* Setup wanpipe as a router (WANPIPE) or as an API */ | ||
| 836 | if( strcmp(conf->usedby, "WANPIPE") == 0) { | ||
| 837 | |||
| 838 | printk(KERN_INFO "%s: Running in WANPIPE mode!\n", | ||
| 839 | wandev->name); | ||
| 840 | card->u.c.usedby = WANPIPE; | ||
| 841 | |||
| 842 | /* Option to bring down the interface when | ||
| 843 | * the link goes down */ | ||
| 844 | if (conf->if_down){ | ||
| 845 | set_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down); | ||
| 846 | printk(KERN_INFO | ||
| 847 | "%s: Dynamic interface configuration enabled\n", | ||
| 848 | card->devname); | ||
| 849 | } | ||
| 850 | |||
| 851 | } else if( strcmp(conf->usedby, "API") == 0) { | ||
| 852 | card->u.c.usedby = API; | ||
| 853 | printk(KERN_INFO "%s: Running in API mode !\n", | ||
| 854 | wandev->name); | ||
| 855 | } | ||
| 856 | } | ||
| 857 | |||
| 858 | /* Tells us that if this interface is a | ||
| 859 | * gateway or not */ | ||
| 860 | if ((chdlc_priv_area->gateway = conf->gateway) == WANOPT_YES){ | ||
| 861 | printk(KERN_INFO "%s: Interface %s is set as a gateway.\n", | ||
| 862 | card->devname,card->u.c.if_name); | ||
| 863 | } | ||
| 864 | |||
| 865 | /* Get Multicast Information */ | ||
| 866 | chdlc_priv_area->mc = conf->mc; | ||
| 867 | |||
| 868 | /* prepare network device data space for registration */ | ||
| 869 | strcpy(dev->name,card->u.c.if_name); | ||
| 870 | |||
| 871 | dev->init = &if_init; | ||
| 872 | dev->priv = chdlc_priv_area; | ||
| 873 | |||
| 874 | /* Initialize the polling work routine */ | ||
| 875 | INIT_WORK(&chdlc_priv_area->poll_work, (void*)(void*)chdlc_poll, dev); | ||
| 876 | |||
| 877 | /* Initialize the polling delay timer */ | ||
| 878 | init_timer(&chdlc_priv_area->poll_delay_timer); | ||
| 879 | chdlc_priv_area->poll_delay_timer.data = (unsigned long)dev; | ||
| 880 | chdlc_priv_area->poll_delay_timer.function = chdlc_poll_delay; | ||
| 881 | |||
| 882 | printk(KERN_INFO "\n"); | ||
| 883 | |||
| 884 | return 0; | ||
| 885 | } | ||
| 886 | |||
| 887 | |||
| 888 | /****** Network Device Interface ********************************************/ | ||
| 889 | |||
| 890 | /*============================================================================ | ||
| 891 | * Initialize Linux network interface. | ||
| 892 | * | ||
| 893 | * This routine is called only once for each interface, during Linux network | ||
| 894 | * interface registration. Returning anything but zero will fail interface | ||
| 895 | * registration. | ||
| 896 | */ | ||
| 897 | static int if_init(struct net_device* dev) | ||
| 898 | { | ||
| 899 | chdlc_private_area_t* chdlc_priv_area = dev->priv; | ||
| 900 | sdla_t* card = chdlc_priv_area->card; | ||
| 901 | struct wan_device* wandev = &card->wandev; | ||
| 902 | |||
| 903 | /* Initialize device driver entry points */ | ||
| 904 | dev->open = &if_open; | ||
| 905 | dev->stop = &if_close; | ||
| 906 | dev->hard_header = &if_header; | ||
| 907 | dev->rebuild_header = &if_rebuild_hdr; | ||
| 908 | dev->hard_start_xmit = &if_send; | ||
| 909 | dev->get_stats = &if_stats; | ||
| 910 | dev->tx_timeout = &if_tx_timeout; | ||
| 911 | dev->watchdog_timeo = TX_TIMEOUT; | ||
| 912 | |||
| 913 | /* Initialize media-specific parameters */ | ||
| 914 | dev->flags |= IFF_POINTOPOINT; | ||
| 915 | dev->flags |= IFF_NOARP; | ||
| 916 | |||
| 917 | /* Enable Mulitcasting if user selected */ | ||
| 918 | if (chdlc_priv_area->mc == WANOPT_YES){ | ||
| 919 | dev->flags |= IFF_MULTICAST; | ||
| 920 | } | ||
| 921 | |||
| 922 | if (chdlc_priv_area->true_if_encoding){ | ||
| 923 | dev->type = ARPHRD_HDLC; /* This breaks the tcpdump */ | ||
| 924 | }else{ | ||
| 925 | dev->type = ARPHRD_PPP; | ||
| 926 | } | ||
| 927 | |||
| 928 | dev->mtu = card->wandev.mtu; | ||
| 929 | /* for API usage, add the API header size to the requested MTU size */ | ||
| 930 | if(card->u.c.usedby == API) { | ||
| 931 | dev->mtu += sizeof(api_tx_hdr_t); | ||
| 932 | } | ||
| 933 | |||
| 934 | dev->hard_header_len = CHDLC_HDR_LEN; | ||
| 935 | |||
| 936 | /* Initialize hardware parameters */ | ||
| 937 | dev->irq = wandev->irq; | ||
| 938 | dev->dma = wandev->dma; | ||
| 939 | dev->base_addr = wandev->ioport; | ||
| 940 | dev->mem_start = wandev->maddr; | ||
| 941 | dev->mem_end = wandev->maddr + wandev->msize - 1; | ||
| 942 | |||
| 943 | /* Set transmit buffer queue length | ||
| 944 | * If too low packets will not be retransmitted | ||
| 945 | * by stack. | ||
| 946 | */ | ||
| 947 | dev->tx_queue_len = 100; | ||
| 948 | SET_MODULE_OWNER(dev); | ||
| 949 | |||
| 950 | return 0; | ||
| 951 | } | ||
| 952 | |||
| 953 | /*============================================================================ | ||
| 954 | * Open network interface. | ||
| 955 | * o enable communications and interrupts. | ||
| 956 | * o prevent module from unloading by incrementing use count | ||
| 957 | * | ||
| 958 | * Return 0 if O.k. or errno. | ||
| 959 | */ | ||
| 960 | static int if_open(struct net_device* dev) | ||
| 961 | { | ||
| 962 | chdlc_private_area_t* chdlc_priv_area = dev->priv; | ||
| 963 | sdla_t* card = chdlc_priv_area->card; | ||
| 964 | struct timeval tv; | ||
| 965 | int err = 0; | ||
| 966 | |||
| 967 | /* Only one open per interface is allowed */ | ||
| 968 | |||
| 969 | if (netif_running(dev)) | ||
| 970 | return -EBUSY; | ||
| 971 | |||
| 972 | /* Initialize the work queue entry */ | ||
| 973 | chdlc_priv_area->tq_working=0; | ||
| 974 | |||
| 975 | INIT_WORK(&chdlc_priv_area->common.wanpipe_work, | ||
| 976 | (void *)(void *)chdlc_work, dev); | ||
| 977 | |||
| 978 | /* Allocate and initialize BH circular buffer */ | ||
| 979 | /* Add 1 to MAX_BH_BUFF so we don't have test with (MAX_BH_BUFF-1) */ | ||
| 980 | chdlc_priv_area->bh_head = kmalloc((sizeof(bh_data_t)*(MAX_BH_BUFF+1)),GFP_ATOMIC); | ||
| 981 | memset(chdlc_priv_area->bh_head,0,(sizeof(bh_data_t)*(MAX_BH_BUFF+1))); | ||
| 982 | atomic_set(&chdlc_priv_area->bh_buff_used, 0); | ||
| 983 | |||
| 984 | do_gettimeofday(&tv); | ||
| 985 | chdlc_priv_area->router_start_time = tv.tv_sec; | ||
| 986 | |||
| 987 | netif_start_queue(dev); | ||
| 988 | |||
| 989 | wanpipe_open(card); | ||
| 990 | |||
| 991 | /* TTY is configured during wanpipe_set_termios | ||
| 992 | * call, not here */ | ||
| 993 | if (card->tty_opt) | ||
| 994 | return err; | ||
| 995 | |||
| 996 | set_bit(0,&chdlc_priv_area->config_chdlc); | ||
| 997 | chdlc_priv_area->config_chdlc_timeout=jiffies; | ||
| 998 | |||
| 999 | /* Start the CHDLC configuration after 1sec delay. | ||
| 1000 | * This will give the interface initilization time | ||
| 1001 | * to finish its configuration */ | ||
| 1002 | mod_timer(&chdlc_priv_area->poll_delay_timer, jiffies + HZ); | ||
| 1003 | return err; | ||
| 1004 | } | ||
| 1005 | |||
| 1006 | /*============================================================================ | ||
| 1007 | * Close network interface. | ||
| 1008 | * o if this is the last close, then disable communications and interrupts. | ||
| 1009 | * o reset flags. | ||
| 1010 | */ | ||
| 1011 | static int if_close(struct net_device* dev) | ||
| 1012 | { | ||
| 1013 | chdlc_private_area_t* chdlc_priv_area = dev->priv; | ||
| 1014 | sdla_t* card = chdlc_priv_area->card; | ||
| 1015 | |||
| 1016 | if (chdlc_priv_area->bh_head){ | ||
| 1017 | int i; | ||
| 1018 | struct sk_buff *skb; | ||
| 1019 | |||
| 1020 | for (i=0; i<(MAX_BH_BUFF+1); i++){ | ||
| 1021 | skb = ((bh_data_t *)&chdlc_priv_area->bh_head[i])->skb; | ||
| 1022 | if (skb != NULL){ | ||
| 1023 | dev_kfree_skb_any(skb); | ||
| 1024 | } | ||
| 1025 | } | ||
| 1026 | kfree(chdlc_priv_area->bh_head); | ||
| 1027 | chdlc_priv_area->bh_head=NULL; | ||
| 1028 | } | ||
| 1029 | |||
| 1030 | netif_stop_queue(dev); | ||
| 1031 | wanpipe_close(card); | ||
| 1032 | del_timer(&chdlc_priv_area->poll_delay_timer); | ||
| 1033 | return 0; | ||
| 1034 | } | ||
| 1035 | |||
| 1036 | static void disable_comm (sdla_t *card) | ||
| 1037 | { | ||
| 1038 | SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; | ||
| 1039 | |||
| 1040 | if (card->u.c.comm_enabled){ | ||
| 1041 | chdlc_disable_comm_shutdown (card); | ||
| 1042 | }else{ | ||
| 1043 | flags->interrupt_info_struct.interrupt_permission = 0; | ||
| 1044 | } | ||
| 1045 | |||
| 1046 | if (!tty_init_cnt) | ||
| 1047 | return; | ||
| 1048 | |||
| 1049 | if (card->tty_opt){ | ||
| 1050 | struct serial_state * state; | ||
| 1051 | if (!(--tty_init_cnt)){ | ||
| 1052 | int e1; | ||
| 1053 | serial_driver.refcount=0; | ||
| 1054 | |||
| 1055 | if ((e1 = tty_unregister_driver(&serial_driver))) | ||
| 1056 | printk("SERIAL: failed to unregister serial driver (%d)\n", | ||
| 1057 | e1); | ||
| 1058 | printk(KERN_INFO "%s: Unregistering TTY Driver, Major %i\n", | ||
| 1059 | card->devname,WAN_TTY_MAJOR); | ||
| 1060 | } | ||
| 1061 | card->tty=NULL; | ||
| 1062 | tty_card_map[card->tty_minor]=NULL; | ||
| 1063 | state = &rs_table[card->tty_minor]; | ||
| 1064 | memset(state, 0, sizeof(*state)); | ||
| 1065 | } | ||
| 1066 | return; | ||
| 1067 | } | ||
| 1068 | |||
| 1069 | |||
| 1070 | /*============================================================================ | ||
| 1071 | * Build media header. | ||
| 1072 | * | ||
| 1073 | * The trick here is to put packet type (Ethertype) into 'protocol' field of | ||
| 1074 | * the socket buffer, so that we don't forget it. If packet type is not | ||
| 1075 | * supported, set skb->protocol to 0 and discard packet later. | ||
| 1076 | * | ||
| 1077 | * Return: media header length. | ||
| 1078 | */ | ||
| 1079 | static int if_header(struct sk_buff* skb, struct net_device* dev, | ||
| 1080 | unsigned short type, void* daddr, void* saddr, | ||
| 1081 | unsigned len) | ||
| 1082 | { | ||
| 1083 | skb->protocol = htons(type); | ||
| 1084 | |||
| 1085 | return CHDLC_HDR_LEN; | ||
| 1086 | } | ||
| 1087 | |||
| 1088 | |||
| 1089 | /*============================================================================ | ||
| 1090 | * Handle transmit timeout event from netif watchdog | ||
| 1091 | */ | ||
| 1092 | static void if_tx_timeout(struct net_device *dev) | ||
| 1093 | { | ||
| 1094 | chdlc_private_area_t* chan = dev->priv; | ||
| 1095 | sdla_t *card = chan->card; | ||
| 1096 | |||
| 1097 | /* If our device stays busy for at least 5 seconds then we will | ||
| 1098 | * kick start the device by making dev->tbusy = 0. We expect | ||
| 1099 | * that our device never stays busy more than 5 seconds. So this | ||
| 1100 | * is only used as a last resort. | ||
| 1101 | */ | ||
| 1102 | |||
| 1103 | ++card->wandev.stats.collisions; | ||
| 1104 | |||
| 1105 | printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); | ||
| 1106 | netif_wake_queue (dev); | ||
| 1107 | } | ||
| 1108 | |||
| 1109 | |||
| 1110 | |||
| 1111 | /*============================================================================ | ||
| 1112 | * Re-build media header. | ||
| 1113 | * | ||
| 1114 | * Return: 1 physical address resolved. | ||
| 1115 | * 0 physical address not resolved | ||
| 1116 | */ | ||
| 1117 | static int if_rebuild_hdr (struct sk_buff *skb) | ||
| 1118 | { | ||
| 1119 | return 1; | ||
| 1120 | } | ||
| 1121 | |||
| 1122 | |||
| 1123 | /*============================================================================ | ||
| 1124 | * Send a packet on a network interface. | ||
| 1125 | * o set tbusy flag (marks start of the transmission) to block a timer-based | ||
| 1126 | * transmit from overlapping. | ||
| 1127 | * o check link state. If link is not up, then drop the packet. | ||
| 1128 | * o execute adapter send command. | ||
| 1129 | * o free socket buffer | ||
| 1130 | * | ||
| 1131 | * Return: 0 complete (socket buffer must be freed) | ||
| 1132 | * non-0 packet may be re-transmitted (tbusy must be set) | ||
| 1133 | * | ||
| 1134 | * Notes: | ||
| 1135 | * 1. This routine is called either by the protocol stack or by the "net | ||
| 1136 | * bottom half" (with interrupts enabled). | ||
| 1137 | * 2. Setting tbusy flag will inhibit further transmit requests from the | ||
| 1138 | * protocol stack and can be used for flow control with protocol layer. | ||
| 1139 | */ | ||
| 1140 | static int if_send(struct sk_buff* skb, struct net_device* dev) | ||
| 1141 | { | ||
| 1142 | chdlc_private_area_t *chdlc_priv_area = dev->priv; | ||
| 1143 | sdla_t *card = chdlc_priv_area->card; | ||
| 1144 | SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; | ||
| 1145 | INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct; | ||
| 1146 | int udp_type = 0; | ||
| 1147 | unsigned long smp_flags; | ||
| 1148 | int err=0; | ||
| 1149 | |||
| 1150 | netif_stop_queue(dev); | ||
| 1151 | |||
| 1152 | if (skb == NULL){ | ||
| 1153 | /* If we get here, some higher layer thinks we've missed an | ||
| 1154 | * tx-done interrupt. | ||
| 1155 | */ | ||
| 1156 | printk(KERN_INFO "%s: interface %s got kicked!\n", | ||
| 1157 | card->devname, dev->name); | ||
| 1158 | |||
| 1159 | netif_wake_queue(dev); | ||
| 1160 | return 0; | ||
| 1161 | } | ||
| 1162 | |||
| 1163 | if (ntohs(skb->protocol) != htons(PVC_PROT)){ | ||
| 1164 | |||
| 1165 | /* check the udp packet type */ | ||
| 1166 | |||
| 1167 | udp_type = udp_pkt_type(skb, card); | ||
| 1168 | |||
| 1169 | if (udp_type == UDP_CPIPE_TYPE){ | ||
| 1170 | if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, | ||
| 1171 | chdlc_priv_area)){ | ||
| 1172 | chdlc_int->interrupt_permission |= | ||
| 1173 | APP_INT_ON_TIMER; | ||
| 1174 | } | ||
| 1175 | netif_start_queue(dev); | ||
| 1176 | return 0; | ||
| 1177 | } | ||
| 1178 | |||
| 1179 | /* check to see if the source IP address is a broadcast or */ | ||
| 1180 | /* multicast IP address */ | ||
| 1181 | if(chk_bcast_mcast_addr(card, dev, skb)){ | ||
| 1182 | ++card->wandev.stats.tx_dropped; | ||
| 1183 | dev_kfree_skb_any(skb); | ||
| 1184 | netif_start_queue(dev); | ||
| 1185 | return 0; | ||
| 1186 | } | ||
| 1187 | } | ||
| 1188 | |||
| 1189 | /* Lock the 508 Card: SMP is supported */ | ||
| 1190 | if(card->hw.type != SDLA_S514){ | ||
| 1191 | s508_lock(card,&smp_flags); | ||
| 1192 | } | ||
| 1193 | |||
| 1194 | if(test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) { | ||
| 1195 | |||
| 1196 | printk(KERN_INFO "%s: Critical in if_send: %lx\n", | ||
| 1197 | card->wandev.name,card->wandev.critical); | ||
| 1198 | ++card->wandev.stats.tx_dropped; | ||
| 1199 | netif_start_queue(dev); | ||
| 1200 | goto if_send_exit_crit; | ||
| 1201 | } | ||
| 1202 | |||
| 1203 | if(card->u.c.state != WAN_CONNECTED){ | ||
| 1204 | ++card->wandev.stats.tx_dropped; | ||
| 1205 | netif_start_queue(dev); | ||
| 1206 | |||
| 1207 | }else if(!skb->protocol){ | ||
| 1208 | ++card->wandev.stats.tx_errors; | ||
| 1209 | netif_start_queue(dev); | ||
| 1210 | |||
| 1211 | }else { | ||
| 1212 | void* data = skb->data; | ||
| 1213 | unsigned len = skb->len; | ||
| 1214 | unsigned char attr; | ||
| 1215 | |||
| 1216 | /* If it's an API packet pull off the API | ||
| 1217 | * header. Also check that the packet size | ||
| 1218 | * is larger than the API header | ||
| 1219 | */ | ||
| 1220 | if (card->u.c.usedby == API){ | ||
| 1221 | api_tx_hdr_t* api_tx_hdr; | ||
| 1222 | |||
| 1223 | /* discard the frame if we are configured for */ | ||
| 1224 | /* 'receive only' mode or if there is no data */ | ||
| 1225 | if (card->u.c.receive_only || | ||
| 1226 | (len <= sizeof(api_tx_hdr_t))) { | ||
| 1227 | |||
| 1228 | ++card->wandev.stats.tx_dropped; | ||
| 1229 | netif_start_queue(dev); | ||
| 1230 | goto if_send_exit_crit; | ||
| 1231 | } | ||
| 1232 | |||
| 1233 | api_tx_hdr = (api_tx_hdr_t *)data; | ||
| 1234 | attr = api_tx_hdr->attr; | ||
| 1235 | data += sizeof(api_tx_hdr_t); | ||
| 1236 | len -= sizeof(api_tx_hdr_t); | ||
| 1237 | } | ||
| 1238 | |||
| 1239 | if(chdlc_send(card, data, len)) { | ||
| 1240 | netif_stop_queue(dev); | ||
| 1241 | }else{ | ||
| 1242 | ++card->wandev.stats.tx_packets; | ||
| 1243 | card->wandev.stats.tx_bytes += len; | ||
| 1244 | |||
| 1245 | netif_start_queue(dev); | ||
| 1246 | |||
| 1247 | dev->trans_start = jiffies; | ||
| 1248 | } | ||
| 1249 | } | ||
| 1250 | |||
| 1251 | if_send_exit_crit: | ||
| 1252 | |||
| 1253 | if (!(err=netif_queue_stopped(dev))) { | ||
| 1254 | dev_kfree_skb_any(skb); | ||
| 1255 | }else{ | ||
| 1256 | chdlc_priv_area->tick_counter = jiffies; | ||
| 1257 | chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME; | ||
| 1258 | } | ||
| 1259 | |||
| 1260 | clear_bit(SEND_CRIT, (void*)&card->wandev.critical); | ||
| 1261 | if(card->hw.type != SDLA_S514){ | ||
| 1262 | s508_unlock(card,&smp_flags); | ||
| 1263 | } | ||
| 1264 | |||
| 1265 | return err; | ||
| 1266 | } | ||
| 1267 | |||
| 1268 | |||
| 1269 | /*============================================================================ | ||
| 1270 | * Check to see if the packet to be transmitted contains a broadcast or | ||
| 1271 | * multicast source IP address. | ||
| 1272 | */ | ||
| 1273 | |||
| 1274 | static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, | ||
| 1275 | struct sk_buff *skb) | ||
| 1276 | { | ||
| 1277 | u32 src_ip_addr; | ||
| 1278 | u32 broadcast_ip_addr = 0; | ||
| 1279 | struct in_device *in_dev; | ||
| 1280 | |||
| 1281 | /* read the IP source address from the outgoing packet */ | ||
| 1282 | src_ip_addr = *(u32 *)(skb->data + 12); | ||
| 1283 | |||
| 1284 | /* read the IP broadcast address for the device */ | ||
| 1285 | in_dev = dev->ip_ptr; | ||
| 1286 | if(in_dev != NULL) { | ||
| 1287 | struct in_ifaddr *ifa= in_dev->ifa_list; | ||
| 1288 | if(ifa != NULL) | ||
| 1289 | broadcast_ip_addr = ifa->ifa_broadcast; | ||
| 1290 | else | ||
| 1291 | return 0; | ||
| 1292 | } | ||
| 1293 | |||
| 1294 | /* check if the IP Source Address is a Broadcast address */ | ||
| 1295 | if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { | ||
| 1296 | printk(KERN_INFO "%s: Broadcast Source Address silently discarded\n", | ||
| 1297 | card->devname); | ||
| 1298 | return 1; | ||
| 1299 | } | ||
| 1300 | |||
| 1301 | /* check if the IP Source Address is a Multicast address */ | ||
| 1302 | if((ntohl(src_ip_addr) >= 0xE0000001) && | ||
| 1303 | (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { | ||
| 1304 | printk(KERN_INFO "%s: Multicast Source Address silently discarded\n", | ||
| 1305 | card->devname); | ||
| 1306 | return 1; | ||
| 1307 | } | ||
| 1308 | |||
| 1309 | return 0; | ||
| 1310 | } | ||
| 1311 | |||
| 1312 | |||
| 1313 | /*============================================================================ | ||
| 1314 | * Reply to UDP Management system. | ||
| 1315 | * Return length of reply. | ||
| 1316 | */ | ||
| 1317 | static int reply_udp( unsigned char *data, unsigned int mbox_len ) | ||
| 1318 | { | ||
| 1319 | |||
| 1320 | unsigned short len, udp_length, temp, ip_length; | ||
| 1321 | unsigned long ip_temp; | ||
| 1322 | int even_bound = 0; | ||
| 1323 | chdlc_udp_pkt_t *c_udp_pkt = (chdlc_udp_pkt_t *)data; | ||
| 1324 | |||
| 1325 | /* Set length of packet */ | ||
| 1326 | len = sizeof(ip_pkt_t)+ | ||
| 1327 | sizeof(udp_pkt_t)+ | ||
| 1328 | sizeof(wp_mgmt_t)+ | ||
| 1329 | sizeof(cblock_t)+ | ||
| 1330 | sizeof(trace_info_t)+ | ||
| 1331 | mbox_len; | ||
| 1332 | |||
| 1333 | /* fill in UDP reply */ | ||
| 1334 | c_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; | ||
| 1335 | |||
| 1336 | /* fill in UDP length */ | ||
| 1337 | udp_length = sizeof(udp_pkt_t)+ | ||
| 1338 | sizeof(wp_mgmt_t)+ | ||
| 1339 | sizeof(cblock_t)+ | ||
| 1340 | sizeof(trace_info_t)+ | ||
| 1341 | mbox_len; | ||
| 1342 | |||
| 1343 | /* put it on an even boundary */ | ||
| 1344 | if ( udp_length & 0x0001 ) { | ||
| 1345 | udp_length += 1; | ||
| 1346 | len += 1; | ||
| 1347 | even_bound = 1; | ||
| 1348 | } | ||
| 1349 | |||
| 1350 | temp = (udp_length<<8)|(udp_length>>8); | ||
| 1351 | c_udp_pkt->udp_pkt.udp_length = temp; | ||
| 1352 | |||
| 1353 | /* swap UDP ports */ | ||
| 1354 | temp = c_udp_pkt->udp_pkt.udp_src_port; | ||
| 1355 | c_udp_pkt->udp_pkt.udp_src_port = | ||
| 1356 | c_udp_pkt->udp_pkt.udp_dst_port; | ||
| 1357 | c_udp_pkt->udp_pkt.udp_dst_port = temp; | ||
| 1358 | |||
| 1359 | /* add UDP pseudo header */ | ||
| 1360 | temp = 0x1100; | ||
| 1361 | *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound)) = temp; | ||
| 1362 | temp = (udp_length<<8)|(udp_length>>8); | ||
| 1363 | *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound+2)) = temp; | ||
| 1364 | |||
| 1365 | |||
| 1366 | /* calculate UDP checksum */ | ||
| 1367 | c_udp_pkt->udp_pkt.udp_checksum = 0; | ||
| 1368 | c_udp_pkt->udp_pkt.udp_checksum = calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET); | ||
| 1369 | |||
| 1370 | /* fill in IP length */ | ||
| 1371 | ip_length = len; | ||
| 1372 | temp = (ip_length<<8)|(ip_length>>8); | ||
| 1373 | c_udp_pkt->ip_pkt.total_length = temp; | ||
| 1374 | |||
| 1375 | /* swap IP addresses */ | ||
| 1376 | ip_temp = c_udp_pkt->ip_pkt.ip_src_address; | ||
| 1377 | c_udp_pkt->ip_pkt.ip_src_address = c_udp_pkt->ip_pkt.ip_dst_address; | ||
| 1378 | c_udp_pkt->ip_pkt.ip_dst_address = ip_temp; | ||
| 1379 | |||
| 1380 | /* fill in IP checksum */ | ||
| 1381 | c_udp_pkt->ip_pkt.hdr_checksum = 0; | ||
| 1382 | c_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data,sizeof(ip_pkt_t)); | ||
| 1383 | |||
| 1384 | return len; | ||
| 1385 | |||
| 1386 | } /* reply_udp */ | ||
| 1387 | |||
| 1388 | unsigned short calc_checksum (char *data, int len) | ||
| 1389 | { | ||
| 1390 | unsigned short temp; | ||
| 1391 | unsigned long sum=0; | ||
| 1392 | int i; | ||
| 1393 | |||
| 1394 | for( i = 0; i <len; i+=2 ) { | ||
| 1395 | memcpy(&temp,&data[i],2); | ||
| 1396 | sum += (unsigned long)temp; | ||
| 1397 | } | ||
| 1398 | |||
| 1399 | while (sum >> 16 ) { | ||
| 1400 | sum = (sum & 0xffffUL) + (sum >> 16); | ||
| 1401 | } | ||
| 1402 | |||
| 1403 | temp = (unsigned short)sum; | ||
| 1404 | temp = ~temp; | ||
| 1405 | |||
| 1406 | if( temp == 0 ) | ||
| 1407 | temp = 0xffff; | ||
| 1408 | |||
| 1409 | return temp; | ||
| 1410 | } | ||
| 1411 | |||
| 1412 | |||
| 1413 | /*============================================================================ | ||
| 1414 | * Get ethernet-style interface statistics. | ||
| 1415 | * Return a pointer to struct enet_statistics. | ||
| 1416 | */ | ||
| 1417 | static struct net_device_stats* if_stats(struct net_device* dev) | ||
| 1418 | { | ||
| 1419 | sdla_t *my_card; | ||
| 1420 | chdlc_private_area_t* chdlc_priv_area; | ||
| 1421 | |||
| 1422 | if ((chdlc_priv_area=dev->priv) == NULL) | ||
| 1423 | return NULL; | ||
| 1424 | |||
| 1425 | my_card = chdlc_priv_area->card; | ||
| 1426 | return &my_card->wandev.stats; | ||
| 1427 | } | ||
| 1428 | |||
| 1429 | |||
| 1430 | /****** Cisco HDLC Firmware Interface Functions *******************************/ | ||
| 1431 | |||
| 1432 | /*============================================================================ | ||
| 1433 | * Read firmware code version. | ||
| 1434 | * Put code version as ASCII string in str. | ||
| 1435 | */ | ||
| 1436 | static int chdlc_read_version (sdla_t* card, char* str) | ||
| 1437 | { | ||
| 1438 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
| 1439 | int len; | ||
| 1440 | char err; | ||
| 1441 | mb->buffer_length = 0; | ||
| 1442 | mb->command = READ_CHDLC_CODE_VERSION; | ||
| 1443 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 1444 | |||
| 1445 | if(err != COMMAND_OK) { | ||
| 1446 | chdlc_error(card,err,mb); | ||
| 1447 | } | ||
| 1448 | else if (str) { /* is not null */ | ||
| 1449 | len = mb->buffer_length; | ||
| 1450 | memcpy(str, mb->data, len); | ||
| 1451 | str[len] = '\0'; | ||
| 1452 | } | ||
| 1453 | return (err); | ||
| 1454 | } | ||
| 1455 | |||
| 1456 | /*----------------------------------------------------------------------------- | ||
| 1457 | * Configure CHDLC firmware. | ||
| 1458 | */ | ||
| 1459 | static int chdlc_configure (sdla_t* card, void* data) | ||
| 1460 | { | ||
| 1461 | int err; | ||
| 1462 | CHDLC_MAILBOX_STRUCT *mailbox = card->mbox; | ||
| 1463 | int data_length = sizeof(CHDLC_CONFIGURATION_STRUCT); | ||
| 1464 | |||
| 1465 | mailbox->buffer_length = data_length; | ||
| 1466 | memcpy(mailbox->data, data, data_length); | ||
| 1467 | mailbox->command = SET_CHDLC_CONFIGURATION; | ||
| 1468 | err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT; | ||
| 1469 | |||
| 1470 | if (err != COMMAND_OK) chdlc_error (card, err, mailbox); | ||
| 1471 | |||
| 1472 | return err; | ||
| 1473 | } | ||
| 1474 | |||
| 1475 | |||
| 1476 | /*============================================================================ | ||
| 1477 | * Set interrupt mode -- HDLC Version. | ||
| 1478 | */ | ||
| 1479 | |||
| 1480 | static int chdlc_set_intr_mode (sdla_t* card, unsigned mode) | ||
| 1481 | { | ||
| 1482 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
| 1483 | CHDLC_INT_TRIGGERS_STRUCT* int_data = | ||
| 1484 | (CHDLC_INT_TRIGGERS_STRUCT *)mb->data; | ||
| 1485 | int err; | ||
| 1486 | |||
| 1487 | int_data->CHDLC_interrupt_triggers = mode; | ||
| 1488 | int_data->IRQ = card->hw.irq; | ||
| 1489 | int_data->interrupt_timer = 1; | ||
| 1490 | |||
| 1491 | mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT); | ||
| 1492 | mb->command = SET_CHDLC_INTERRUPT_TRIGGERS; | ||
| 1493 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 1494 | if (err != COMMAND_OK) | ||
| 1495 | chdlc_error (card, err, mb); | ||
| 1496 | return err; | ||
| 1497 | } | ||
| 1498 | |||
| 1499 | |||
| 1500 | /*=========================================================== | ||
| 1501 | * chdlc_disable_comm_shutdown | ||
| 1502 | * | ||
| 1503 | * Shutdown() disables the communications. We must | ||
| 1504 | * have a sparate functions, because we must not | ||
| 1505 | * call chdlc_error() hander since the private | ||
| 1506 | * area has already been replaced */ | ||
| 1507 | |||
| 1508 | static int chdlc_disable_comm_shutdown (sdla_t *card) | ||
| 1509 | { | ||
| 1510 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
| 1511 | CHDLC_INT_TRIGGERS_STRUCT* int_data = | ||
| 1512 | (CHDLC_INT_TRIGGERS_STRUCT *)mb->data; | ||
| 1513 | int err; | ||
| 1514 | |||
| 1515 | /* Disable Interrutps */ | ||
| 1516 | int_data->CHDLC_interrupt_triggers = 0; | ||
| 1517 | int_data->IRQ = card->hw.irq; | ||
| 1518 | int_data->interrupt_timer = 1; | ||
| 1519 | |||
| 1520 | mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT); | ||
| 1521 | mb->command = SET_CHDLC_INTERRUPT_TRIGGERS; | ||
| 1522 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 1523 | |||
| 1524 | /* Disable Communications */ | ||
| 1525 | |||
| 1526 | if (card->u.c.async_mode) { | ||
| 1527 | mb->command = DISABLE_ASY_COMMUNICATIONS; | ||
| 1528 | }else{ | ||
| 1529 | mb->command = DISABLE_CHDLC_COMMUNICATIONS; | ||
| 1530 | } | ||
| 1531 | |||
| 1532 | mb->buffer_length = 0; | ||
| 1533 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 1534 | |||
| 1535 | card->u.c.comm_enabled = 0; | ||
| 1536 | |||
| 1537 | return 0; | ||
| 1538 | } | ||
| 1539 | |||
| 1540 | /*============================================================================ | ||
| 1541 | * Enable communications. | ||
| 1542 | */ | ||
| 1543 | |||
| 1544 | static int chdlc_comm_enable (sdla_t* card) | ||
| 1545 | { | ||
| 1546 | int err; | ||
| 1547 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
| 1548 | |||
| 1549 | mb->buffer_length = 0; | ||
| 1550 | mb->command = ENABLE_CHDLC_COMMUNICATIONS; | ||
| 1551 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 1552 | if (err != COMMAND_OK) | ||
| 1553 | chdlc_error(card, err, mb); | ||
| 1554 | else | ||
| 1555 | card->u.c.comm_enabled = 1; | ||
| 1556 | |||
| 1557 | return err; | ||
| 1558 | } | ||
| 1559 | |||
| 1560 | /*============================================================================ | ||
| 1561 | * Read communication error statistics. | ||
| 1562 | */ | ||
| 1563 | static int chdlc_read_comm_err_stats (sdla_t* card) | ||
| 1564 | { | ||
| 1565 | int err; | ||
| 1566 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
| 1567 | |||
| 1568 | mb->buffer_length = 0; | ||
| 1569 | mb->command = READ_COMMS_ERROR_STATS; | ||
| 1570 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 1571 | if (err != COMMAND_OK) | ||
| 1572 | chdlc_error(card,err,mb); | ||
| 1573 | return err; | ||
| 1574 | } | ||
| 1575 | |||
| 1576 | |||
| 1577 | /*============================================================================ | ||
| 1578 | * Read CHDLC operational statistics. | ||
| 1579 | */ | ||
| 1580 | static int chdlc_read_op_stats (sdla_t* card) | ||
| 1581 | { | ||
| 1582 | int err; | ||
| 1583 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
| 1584 | |||
| 1585 | mb->buffer_length = 0; | ||
| 1586 | mb->command = READ_CHDLC_OPERATIONAL_STATS; | ||
| 1587 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 1588 | if (err != COMMAND_OK) | ||
| 1589 | chdlc_error(card,err,mb); | ||
| 1590 | return err; | ||
| 1591 | } | ||
| 1592 | |||
| 1593 | |||
| 1594 | /*============================================================================ | ||
| 1595 | * Update communications error and general packet statistics. | ||
| 1596 | */ | ||
| 1597 | static int update_comms_stats(sdla_t* card, | ||
| 1598 | chdlc_private_area_t* chdlc_priv_area) | ||
| 1599 | { | ||
| 1600 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
| 1601 | COMMS_ERROR_STATS_STRUCT* err_stats; | ||
| 1602 | CHDLC_OPERATIONAL_STATS_STRUCT *op_stats; | ||
| 1603 | |||
| 1604 | /* on the first timer interrupt, read the comms error statistics */ | ||
| 1605 | if(chdlc_priv_area->update_comms_stats == 2) { | ||
| 1606 | if(chdlc_read_comm_err_stats(card)) | ||
| 1607 | return 1; | ||
| 1608 | err_stats = (COMMS_ERROR_STATS_STRUCT *)mb->data; | ||
| 1609 | card->wandev.stats.rx_over_errors = | ||
| 1610 | err_stats->Rx_overrun_err_count; | ||
| 1611 | card->wandev.stats.rx_crc_errors = | ||
| 1612 | err_stats->CRC_err_count; | ||
| 1613 | card->wandev.stats.rx_frame_errors = | ||
| 1614 | err_stats->Rx_abort_count; | ||
| 1615 | card->wandev.stats.rx_fifo_errors = | ||
| 1616 | err_stats->Rx_dis_pri_bfrs_full_count; | ||
| 1617 | card->wandev.stats.rx_missed_errors = | ||
| 1618 | card->wandev.stats.rx_fifo_errors; | ||
| 1619 | card->wandev.stats.tx_aborted_errors = | ||
| 1620 | err_stats->sec_Tx_abort_count; | ||
| 1621 | } | ||
| 1622 | |||
| 1623 | /* on the second timer interrupt, read the operational statistics */ | ||
| 1624 | else { | ||
| 1625 | if(chdlc_read_op_stats(card)) | ||
| 1626 | return 1; | ||
| 1627 | op_stats = (CHDLC_OPERATIONAL_STATS_STRUCT *)mb->data; | ||
| 1628 | card->wandev.stats.rx_length_errors = | ||
| 1629 | (op_stats->Rx_Data_discard_short_count + | ||
| 1630 | op_stats->Rx_Data_discard_long_count); | ||
| 1631 | } | ||
| 1632 | |||
| 1633 | return 0; | ||
| 1634 | } | ||
| 1635 | |||
| 1636 | /*============================================================================ | ||
| 1637 | * Send packet. | ||
| 1638 | * Return: 0 - o.k. | ||
| 1639 | * 1 - no transmit buffers available | ||
| 1640 | */ | ||
| 1641 | static int chdlc_send (sdla_t* card, void* data, unsigned len) | ||
| 1642 | { | ||
| 1643 | CHDLC_DATA_TX_STATUS_EL_STRUCT *txbuf = card->u.c.txbuf; | ||
| 1644 | |||
| 1645 | if (txbuf->opp_flag) | ||
| 1646 | return 1; | ||
| 1647 | |||
| 1648 | sdla_poke(&card->hw, txbuf->ptr_data_bfr, data, len); | ||
| 1649 | |||
| 1650 | txbuf->frame_length = len; | ||
| 1651 | txbuf->opp_flag = 1; /* start transmission */ | ||
| 1652 | |||
| 1653 | /* Update transmit buffer control fields */ | ||
| 1654 | card->u.c.txbuf = ++txbuf; | ||
| 1655 | |||
| 1656 | if ((void*)txbuf > card->u.c.txbuf_last) | ||
| 1657 | card->u.c.txbuf = card->u.c.txbuf_base; | ||
| 1658 | |||
| 1659 | return 0; | ||
| 1660 | } | ||
| 1661 | |||
| 1662 | /****** Firmware Error Handler **********************************************/ | ||
| 1663 | |||
| 1664 | /*============================================================================ | ||
| 1665 | * Firmware error handler. | ||
| 1666 | * This routine is called whenever firmware command returns non-zero | ||
| 1667 | * return code. | ||
| 1668 | * | ||
| 1669 | * Return zero if previous command has to be cancelled. | ||
| 1670 | */ | ||
| 1671 | static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb) | ||
| 1672 | { | ||
| 1673 | unsigned cmd = mb->command; | ||
| 1674 | |||
| 1675 | switch (err) { | ||
| 1676 | |||
| 1677 | case CMD_TIMEOUT: | ||
| 1678 | printk(KERN_INFO "%s: command 0x%02X timed out!\n", | ||
| 1679 | card->devname, cmd); | ||
| 1680 | break; | ||
| 1681 | |||
| 1682 | case S514_BOTH_PORTS_SAME_CLK_MODE: | ||
| 1683 | if(cmd == SET_CHDLC_CONFIGURATION) { | ||
| 1684 | printk(KERN_INFO | ||
| 1685 | "%s: Configure both ports for the same clock source\n", | ||
| 1686 | card->devname); | ||
| 1687 | break; | ||
| 1688 | } | ||
| 1689 | |||
| 1690 | default: | ||
| 1691 | printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", | ||
| 1692 | card->devname, cmd, err); | ||
| 1693 | } | ||
| 1694 | |||
| 1695 | return 0; | ||
| 1696 | } | ||
| 1697 | |||
| 1698 | |||
| 1699 | /********** Bottom Half Handlers ********************************************/ | ||
| 1700 | |||
| 1701 | /* NOTE: There is no API, BH support for Kernels lower than 2.2.X. | ||
| 1702 | * DO NOT INSERT ANY CODE HERE, NOTICE THE | ||
| 1703 | * PREPROCESSOR STATEMENT ABOVE, UNLESS YOU KNOW WHAT YOU ARE | ||
| 1704 | * DOING */ | ||
| 1705 | |||
| 1706 | static void chdlc_work(struct net_device * dev) | ||
| 1707 | { | ||
| 1708 | chdlc_private_area_t* chan = dev->priv; | ||
| 1709 | sdla_t *card = chan->card; | ||
| 1710 | struct sk_buff *skb; | ||
| 1711 | |||
| 1712 | if (atomic_read(&chan->bh_buff_used) == 0){ | ||
| 1713 | clear_bit(0, &chan->tq_working); | ||
| 1714 | return; | ||
| 1715 | } | ||
| 1716 | |||
| 1717 | while (atomic_read(&chan->bh_buff_used)){ | ||
| 1718 | |||
| 1719 | skb = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb; | ||
| 1720 | |||
| 1721 | if (skb != NULL){ | ||
| 1722 | |||
| 1723 | if (chan->common.sk == NULL || chan->common.func == NULL){ | ||
| 1724 | ++card->wandev.stats.rx_dropped; | ||
| 1725 | dev_kfree_skb_any(skb); | ||
| 1726 | chdlc_work_cleanup(dev); | ||
| 1727 | continue; | ||
| 1728 | } | ||
| 1729 | |||
| 1730 | if (chan->common.func(skb,dev,chan->common.sk) != 0){ | ||
| 1731 | /* Sock full cannot send, queue us for another | ||
| 1732 | * try */ | ||
| 1733 | atomic_set(&chan->common.receive_block,1); | ||
| 1734 | return; | ||
| 1735 | }else{ | ||
| 1736 | chdlc_work_cleanup(dev); | ||
| 1737 | } | ||
| 1738 | }else{ | ||
| 1739 | chdlc_work_cleanup(dev); | ||
| 1740 | } | ||
| 1741 | } | ||
| 1742 | clear_bit(0, &chan->tq_working); | ||
| 1743 | |||
| 1744 | return; | ||
| 1745 | } | ||
| 1746 | |||
| 1747 | static int chdlc_work_cleanup(struct net_device *dev) | ||
| 1748 | { | ||
| 1749 | chdlc_private_area_t* chan = dev->priv; | ||
| 1750 | |||
| 1751 | ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL; | ||
| 1752 | |||
| 1753 | if (chan->bh_read == MAX_BH_BUFF){ | ||
| 1754 | chan->bh_read=0; | ||
| 1755 | }else{ | ||
| 1756 | ++chan->bh_read; | ||
| 1757 | } | ||
| 1758 | |||
| 1759 | atomic_dec(&chan->bh_buff_used); | ||
| 1760 | return 0; | ||
| 1761 | } | ||
| 1762 | |||
| 1763 | |||
| 1764 | |||
| 1765 | static int bh_enqueue(struct net_device *dev, struct sk_buff *skb) | ||
| 1766 | { | ||
| 1767 | /* Check for full */ | ||
| 1768 | chdlc_private_area_t* chan = dev->priv; | ||
| 1769 | sdla_t *card = chan->card; | ||
| 1770 | |||
| 1771 | if (atomic_read(&chan->bh_buff_used) == (MAX_BH_BUFF+1)){ | ||
| 1772 | ++card->wandev.stats.rx_dropped; | ||
| 1773 | dev_kfree_skb_any(skb); | ||
| 1774 | return 1; | ||
| 1775 | } | ||
| 1776 | |||
| 1777 | ((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb; | ||
| 1778 | |||
| 1779 | if (chan->bh_write == MAX_BH_BUFF){ | ||
| 1780 | chan->bh_write=0; | ||
| 1781 | }else{ | ||
| 1782 | ++chan->bh_write; | ||
| 1783 | } | ||
| 1784 | |||
| 1785 | atomic_inc(&chan->bh_buff_used); | ||
| 1786 | |||
| 1787 | return 0; | ||
| 1788 | } | ||
| 1789 | |||
| 1790 | /* END OF API BH Support */ | ||
| 1791 | |||
| 1792 | |||
| 1793 | /****** Interrupt Handlers **************************************************/ | ||
| 1794 | |||
| 1795 | /*============================================================================ | ||
| 1796 | * Cisco HDLC interrupt service routine. | ||
| 1797 | */ | ||
| 1798 | static void wpc_isr (sdla_t* card) | ||
| 1799 | { | ||
| 1800 | struct net_device* dev; | ||
| 1801 | SHARED_MEMORY_INFO_STRUCT* flags = NULL; | ||
| 1802 | int i; | ||
| 1803 | sdla_t *my_card; | ||
| 1804 | |||
| 1805 | |||
| 1806 | /* Check for which port the interrupt has been generated | ||
| 1807 | * Since Secondary Port is piggybacking on the Primary | ||
| 1808 | * the check must be done here. | ||
| 1809 | */ | ||
| 1810 | |||
| 1811 | flags = card->u.c.flags; | ||
| 1812 | if (!flags->interrupt_info_struct.interrupt_type){ | ||
| 1813 | /* Check for a second port (piggybacking) */ | ||
| 1814 | if ((my_card = card->next)){ | ||
| 1815 | flags = my_card->u.c.flags; | ||
| 1816 | if (flags->interrupt_info_struct.interrupt_type){ | ||
| 1817 | card = my_card; | ||
| 1818 | card->isr(card); | ||
| 1819 | return; | ||
| 1820 | } | ||
| 1821 | } | ||
| 1822 | } | ||
| 1823 | |||
| 1824 | flags = card->u.c.flags; | ||
| 1825 | card->in_isr = 1; | ||
| 1826 | dev = card->wandev.dev; | ||
| 1827 | |||
| 1828 | /* If we get an interrupt with no network device, stop the interrupts | ||
| 1829 | * and issue an error */ | ||
| 1830 | if (!card->tty_opt && !dev && | ||
| 1831 | flags->interrupt_info_struct.interrupt_type != | ||
| 1832 | COMMAND_COMPLETE_APP_INT_PEND){ | ||
| 1833 | |||
| 1834 | goto isr_done; | ||
| 1835 | } | ||
| 1836 | |||
| 1837 | /* if critical due to peripheral operations | ||
| 1838 | * ie. update() or getstats() then reset the interrupt and | ||
| 1839 | * wait for the board to retrigger. | ||
| 1840 | */ | ||
| 1841 | if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { | ||
| 1842 | printk(KERN_INFO "ISR CRIT TO PERI\n"); | ||
| 1843 | goto isr_done; | ||
| 1844 | } | ||
| 1845 | |||
| 1846 | /* On a 508 Card, if critical due to if_send | ||
| 1847 | * Major Error !!! */ | ||
| 1848 | if(card->hw.type != SDLA_S514) { | ||
| 1849 | if(test_bit(SEND_CRIT, (void*)&card->wandev.critical)) { | ||
| 1850 | printk(KERN_INFO "%s: Critical while in ISR: %lx\n", | ||
| 1851 | card->devname, card->wandev.critical); | ||
| 1852 | card->in_isr = 0; | ||
| 1853 | flags->interrupt_info_struct.interrupt_type = 0; | ||
| 1854 | return; | ||
| 1855 | } | ||
| 1856 | } | ||
| 1857 | |||
| 1858 | switch(flags->interrupt_info_struct.interrupt_type) { | ||
| 1859 | |||
| 1860 | case RX_APP_INT_PEND: /* 0x01: receive interrupt */ | ||
| 1861 | rx_intr(card); | ||
| 1862 | break; | ||
| 1863 | |||
| 1864 | case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ | ||
| 1865 | flags->interrupt_info_struct.interrupt_permission &= | ||
| 1866 | ~APP_INT_ON_TX_FRAME; | ||
| 1867 | |||
| 1868 | if (card->tty_opt){ | ||
| 1869 | wanpipe_tty_trigger_poll(card); | ||
| 1870 | break; | ||
| 1871 | } | ||
| 1872 | |||
| 1873 | if (dev && netif_queue_stopped(dev)){ | ||
| 1874 | if (card->u.c.usedby == API){ | ||
| 1875 | netif_start_queue(dev); | ||
| 1876 | wakeup_sk_bh(dev); | ||
| 1877 | }else{ | ||
| 1878 | netif_wake_queue(dev); | ||
| 1879 | } | ||
| 1880 | } | ||
| 1881 | break; | ||
| 1882 | |||
| 1883 | case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */ | ||
| 1884 | ++ Intr_test_counter; | ||
| 1885 | break; | ||
| 1886 | |||
| 1887 | case CHDLC_EXCEP_COND_APP_INT_PEND: /* 0x20 */ | ||
| 1888 | process_chdlc_exception(card); | ||
| 1889 | break; | ||
| 1890 | |||
| 1891 | case GLOBAL_EXCEP_COND_APP_INT_PEND: | ||
| 1892 | process_global_exception(card); | ||
| 1893 | break; | ||
| 1894 | |||
| 1895 | case TIMER_APP_INT_PEND: | ||
| 1896 | timer_intr(card); | ||
| 1897 | break; | ||
| 1898 | |||
| 1899 | default: | ||
| 1900 | printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", | ||
| 1901 | card->devname, | ||
| 1902 | flags->interrupt_info_struct.interrupt_type); | ||
| 1903 | printk(KERN_INFO "Code name: "); | ||
| 1904 | for(i = 0; i < 4; i ++) | ||
| 1905 | printk(KERN_INFO "%c", | ||
| 1906 | flags->global_info_struct.codename[i]); | ||
| 1907 | printk(KERN_INFO "\nCode version: "); | ||
| 1908 | for(i = 0; i < 4; i ++) | ||
| 1909 | printk(KERN_INFO "%c", | ||
| 1910 | flags->global_info_struct.codeversion[i]); | ||
| 1911 | printk(KERN_INFO "\n"); | ||
| 1912 | break; | ||
| 1913 | } | ||
| 1914 | |||
| 1915 | isr_done: | ||
| 1916 | |||
| 1917 | card->in_isr = 0; | ||
| 1918 | flags->interrupt_info_struct.interrupt_type = 0; | ||
| 1919 | return; | ||
| 1920 | } | ||
| 1921 | |||
| 1922 | /*============================================================================ | ||
| 1923 | * Receive interrupt handler. | ||
| 1924 | */ | ||
| 1925 | static void rx_intr (sdla_t* card) | ||
| 1926 | { | ||
| 1927 | struct net_device *dev; | ||
| 1928 | chdlc_private_area_t *chdlc_priv_area; | ||
| 1929 | SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; | ||
| 1930 | CHDLC_DATA_RX_STATUS_EL_STRUCT *rxbuf = card->u.c.rxmb; | ||
| 1931 | struct sk_buff *skb; | ||
| 1932 | unsigned len; | ||
| 1933 | unsigned addr = rxbuf->ptr_data_bfr; | ||
| 1934 | void *buf; | ||
| 1935 | int i,udp_type; | ||
| 1936 | |||
| 1937 | if (rxbuf->opp_flag != 0x01) { | ||
| 1938 | printk(KERN_INFO | ||
| 1939 | "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", | ||
| 1940 | card->devname, (unsigned)rxbuf, rxbuf->opp_flag); | ||
| 1941 | printk(KERN_INFO "Code name: "); | ||
| 1942 | for(i = 0; i < 4; i ++) | ||
| 1943 | printk(KERN_INFO "%c", | ||
| 1944 | flags->global_info_struct.codename[i]); | ||
| 1945 | printk(KERN_INFO "\nCode version: "); | ||
| 1946 | for(i = 0; i < 4; i ++) | ||
| 1947 | printk(KERN_INFO "%c", | ||
| 1948 | flags->global_info_struct.codeversion[i]); | ||
| 1949 | printk(KERN_INFO "\n"); | ||
| 1950 | |||
| 1951 | |||
| 1952 | /* Bug Fix: Mar 6 2000 | ||
| 1953 | * If we get a corrupted mailbox, it measn that driver | ||
| 1954 | * is out of sync with the firmware. There is no recovery. | ||
| 1955 | * If we don't turn off all interrupts for this card | ||
| 1956 | * the machine will crash. | ||
| 1957 | */ | ||
| 1958 | printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); | ||
| 1959 | printk(KERN_INFO "Please contact Sangoma Technologies !\n"); | ||
| 1960 | chdlc_set_intr_mode(card,0); | ||
| 1961 | return; | ||
| 1962 | } | ||
| 1963 | |||
| 1964 | len = rxbuf->frame_length; | ||
| 1965 | |||
| 1966 | if (card->tty_opt){ | ||
| 1967 | |||
| 1968 | if (rxbuf->error_flag){ | ||
| 1969 | goto rx_exit; | ||
| 1970 | } | ||
| 1971 | |||
| 1972 | if (len <= CRC_LENGTH){ | ||
| 1973 | goto rx_exit; | ||
| 1974 | } | ||
| 1975 | |||
| 1976 | if (!card->u.c.async_mode){ | ||
| 1977 | len -= CRC_LENGTH; | ||
| 1978 | } | ||
| 1979 | |||
| 1980 | wanpipe_tty_receive(card,addr,len); | ||
| 1981 | goto rx_exit; | ||
| 1982 | } | ||
| 1983 | |||
| 1984 | dev = card->wandev.dev; | ||
| 1985 | |||
| 1986 | if (!dev){ | ||
| 1987 | goto rx_exit; | ||
| 1988 | } | ||
| 1989 | |||
| 1990 | if (!netif_running(dev)) | ||
| 1991 | goto rx_exit; | ||
| 1992 | |||
| 1993 | chdlc_priv_area = dev->priv; | ||
| 1994 | |||
| 1995 | |||
| 1996 | /* Allocate socket buffer */ | ||
| 1997 | skb = dev_alloc_skb(len); | ||
| 1998 | |||
| 1999 | if (skb == NULL) { | ||
| 2000 | printk(KERN_INFO "%s: no socket buffers available!\n", | ||
| 2001 | card->devname); | ||
| 2002 | ++card->wandev.stats.rx_dropped; | ||
| 2003 | goto rx_exit; | ||
| 2004 | } | ||
| 2005 | |||
| 2006 | /* Copy data to the socket buffer */ | ||
| 2007 | if((addr + len) > card->u.c.rx_top + 1) { | ||
| 2008 | unsigned tmp = card->u.c.rx_top - addr + 1; | ||
| 2009 | buf = skb_put(skb, tmp); | ||
| 2010 | sdla_peek(&card->hw, addr, buf, tmp); | ||
| 2011 | addr = card->u.c.rx_base; | ||
| 2012 | len -= tmp; | ||
| 2013 | } | ||
| 2014 | |||
| 2015 | buf = skb_put(skb, len); | ||
| 2016 | sdla_peek(&card->hw, addr, buf, len); | ||
| 2017 | |||
| 2018 | skb->protocol = htons(ETH_P_IP); | ||
| 2019 | |||
| 2020 | card->wandev.stats.rx_packets ++; | ||
| 2021 | card->wandev.stats.rx_bytes += skb->len; | ||
| 2022 | udp_type = udp_pkt_type( skb, card ); | ||
| 2023 | |||
| 2024 | if(udp_type == UDP_CPIPE_TYPE) { | ||
| 2025 | if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, | ||
| 2026 | card, skb, dev, chdlc_priv_area)) { | ||
| 2027 | flags->interrupt_info_struct. | ||
| 2028 | interrupt_permission |= | ||
| 2029 | APP_INT_ON_TIMER; | ||
| 2030 | } | ||
| 2031 | } else if(card->u.c.usedby == API) { | ||
| 2032 | |||
| 2033 | api_rx_hdr_t* api_rx_hdr; | ||
| 2034 | skb_push(skb, sizeof(api_rx_hdr_t)); | ||
| 2035 | api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00]; | ||
| 2036 | api_rx_hdr->error_flag = rxbuf->error_flag; | ||
| 2037 | api_rx_hdr->time_stamp = rxbuf->time_stamp; | ||
| 2038 | |||
| 2039 | skb->protocol = htons(PVC_PROT); | ||
| 2040 | skb->mac.raw = skb->data; | ||
| 2041 | skb->dev = dev; | ||
| 2042 | skb->pkt_type = WAN_PACKET_DATA; | ||
| 2043 | |||
| 2044 | bh_enqueue(dev, skb); | ||
| 2045 | |||
| 2046 | if (!test_and_set_bit(0,&chdlc_priv_area->tq_working)) | ||
| 2047 | wanpipe_queue_work(&chdlc_priv_area->common.wanpipe_work); | ||
| 2048 | }else{ | ||
| 2049 | /* FIXME: we should check to see if the received packet is a | ||
| 2050 | multicast packet so that we can increment the multicast | ||
| 2051 | statistic | ||
| 2052 | ++ chdlc_priv_area->if_stats.multicast; | ||
| 2053 | */ | ||
| 2054 | /* Pass it up the protocol stack */ | ||
| 2055 | |||
| 2056 | skb->dev = dev; | ||
| 2057 | skb->mac.raw = skb->data; | ||
| 2058 | netif_rx(skb); | ||
| 2059 | dev->last_rx = jiffies; | ||
| 2060 | } | ||
| 2061 | |||
| 2062 | rx_exit: | ||
| 2063 | /* Release buffer element and calculate a pointer to the next one */ | ||
| 2064 | rxbuf->opp_flag = 0x00; | ||
| 2065 | card->u.c.rxmb = ++ rxbuf; | ||
| 2066 | if((void*)rxbuf > card->u.c.rxbuf_last){ | ||
| 2067 | card->u.c.rxmb = card->u.c.rxbuf_base; | ||
| 2068 | } | ||
| 2069 | } | ||
| 2070 | |||
| 2071 | /*============================================================================ | ||
| 2072 | * Timer interrupt handler. | ||
| 2073 | * The timer interrupt is used for two purposes: | ||
| 2074 | * 1) Processing udp calls from 'cpipemon'. | ||
| 2075 | * 2) Reading board-level statistics for updating the proc file system. | ||
| 2076 | */ | ||
| 2077 | void timer_intr(sdla_t *card) | ||
| 2078 | { | ||
| 2079 | struct net_device* dev; | ||
| 2080 | chdlc_private_area_t* chdlc_priv_area = NULL; | ||
| 2081 | SHARED_MEMORY_INFO_STRUCT* flags = NULL; | ||
| 2082 | |||
| 2083 | if ((dev = card->wandev.dev)==NULL){ | ||
| 2084 | flags = card->u.c.flags; | ||
| 2085 | flags->interrupt_info_struct.interrupt_permission &= | ||
| 2086 | ~APP_INT_ON_TIMER; | ||
| 2087 | return; | ||
| 2088 | } | ||
| 2089 | |||
| 2090 | chdlc_priv_area = dev->priv; | ||
| 2091 | |||
| 2092 | if (chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG) { | ||
| 2093 | if (!config_chdlc(card)){ | ||
| 2094 | chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG; | ||
| 2095 | } | ||
| 2096 | } | ||
| 2097 | |||
| 2098 | /* process a udp call if pending */ | ||
| 2099 | if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP) { | ||
| 2100 | process_udp_mgmt_pkt(card, dev, | ||
| 2101 | chdlc_priv_area); | ||
| 2102 | chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP; | ||
| 2103 | } | ||
| 2104 | |||
| 2105 | /* read the communications statistics if required */ | ||
| 2106 | if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE) { | ||
| 2107 | update_comms_stats(card, chdlc_priv_area); | ||
| 2108 | if(!(-- chdlc_priv_area->update_comms_stats)) { | ||
| 2109 | chdlc_priv_area->timer_int_enabled &= | ||
| 2110 | ~TMR_INT_ENABLED_UPDATE; | ||
| 2111 | } | ||
| 2112 | } | ||
| 2113 | |||
| 2114 | /* only disable the timer interrupt if there are no udp or statistic */ | ||
| 2115 | /* updates pending */ | ||
| 2116 | if(!chdlc_priv_area->timer_int_enabled) { | ||
| 2117 | flags = card->u.c.flags; | ||
| 2118 | flags->interrupt_info_struct.interrupt_permission &= | ||
| 2119 | ~APP_INT_ON_TIMER; | ||
| 2120 | } | ||
| 2121 | } | ||
| 2122 | |||
| 2123 | /*------------------------------------------------------------------------------ | ||
| 2124 | Miscellaneous Functions | ||
| 2125 | - set_chdlc_config() used to set configuration options on the board | ||
| 2126 | ------------------------------------------------------------------------------*/ | ||
| 2127 | |||
| 2128 | static int set_chdlc_config(sdla_t* card) | ||
| 2129 | { | ||
| 2130 | CHDLC_CONFIGURATION_STRUCT cfg; | ||
| 2131 | |||
| 2132 | memset(&cfg, 0, sizeof(CHDLC_CONFIGURATION_STRUCT)); | ||
| 2133 | |||
| 2134 | if(card->wandev.clocking){ | ||
| 2135 | cfg.baud_rate = card->wandev.bps; | ||
| 2136 | } | ||
| 2137 | |||
| 2138 | cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? | ||
| 2139 | INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; | ||
| 2140 | |||
| 2141 | cfg.modem_config_options = 0; | ||
| 2142 | cfg.modem_status_timer = 100; | ||
| 2143 | |||
| 2144 | cfg.CHDLC_protocol_options = card->u.c.protocol_options; | ||
| 2145 | |||
| 2146 | if (card->tty_opt){ | ||
| 2147 | cfg.CHDLC_API_options = DISCARD_RX_ERROR_FRAMES; | ||
| 2148 | } | ||
| 2149 | |||
| 2150 | cfg.percent_data_buffer_for_Tx = (card->u.c.receive_only) ? 0 : 50; | ||
| 2151 | cfg.CHDLC_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | | ||
| 2152 | CHDLC_RX_DATA_BYTE_COUNT_STAT); | ||
| 2153 | |||
| 2154 | if (card->tty_opt){ | ||
| 2155 | card->wandev.mtu = TTY_CHDLC_MAX_MTU; | ||
| 2156 | } | ||
| 2157 | cfg.max_CHDLC_data_field_length = card->wandev.mtu; | ||
| 2158 | cfg.transmit_keepalive_timer = card->u.c.kpalv_tx; | ||
| 2159 | cfg.receive_keepalive_timer = card->u.c.kpalv_rx; | ||
| 2160 | cfg.keepalive_error_tolerance = card->u.c.kpalv_err; | ||
| 2161 | cfg.SLARP_request_timer = card->u.c.slarp_timer; | ||
| 2162 | |||
| 2163 | if (cfg.SLARP_request_timer) { | ||
| 2164 | cfg.IP_address = 0; | ||
| 2165 | cfg.IP_netmask = 0; | ||
| 2166 | |||
| 2167 | }else if (card->wandev.dev){ | ||
| 2168 | struct net_device *dev = card->wandev.dev; | ||
| 2169 | chdlc_private_area_t *chdlc_priv_area = dev->priv; | ||
| 2170 | |||
| 2171 | struct in_device *in_dev = dev->ip_ptr; | ||
| 2172 | |||
| 2173 | if(in_dev != NULL) { | ||
| 2174 | struct in_ifaddr *ifa = in_dev->ifa_list; | ||
| 2175 | |||
| 2176 | if (ifa != NULL ) { | ||
| 2177 | cfg.IP_address = ntohl(ifa->ifa_local); | ||
| 2178 | cfg.IP_netmask = ntohl(ifa->ifa_mask); | ||
| 2179 | chdlc_priv_area->IP_address = ntohl(ifa->ifa_local); | ||
| 2180 | chdlc_priv_area->IP_netmask = ntohl(ifa->ifa_mask); | ||
| 2181 | } | ||
| 2182 | } | ||
| 2183 | |||
| 2184 | /* FIXME: We must re-think this message in next release | ||
| 2185 | if((cfg.IP_address & 0x000000FF) > 2) { | ||
| 2186 | printk(KERN_WARNING "\n"); | ||
| 2187 | printk(KERN_WARNING " WARNING:%s configured with an\n", | ||
| 2188 | card->devname); | ||
| 2189 | printk(KERN_WARNING " invalid local IP address.\n"); | ||
| 2190 | printk(KERN_WARNING " Slarp pragmatics will fail.\n"); | ||
| 2191 | printk(KERN_WARNING " IP address should be of the\n"); | ||
| 2192 | printk(KERN_WARNING " format A.B.C.1 or A.B.C.2.\n"); | ||
| 2193 | } | ||
| 2194 | */ | ||
| 2195 | } | ||
| 2196 | |||
| 2197 | return chdlc_configure(card, &cfg); | ||
| 2198 | } | ||
| 2199 | |||
| 2200 | |||
| 2201 | /*----------------------------------------------------------------------------- | ||
| 2202 | set_asy_config() used to set asynchronous configuration options on the board | ||
| 2203 | ------------------------------------------------------------------------------*/ | ||
| 2204 | |||
| 2205 | static int set_asy_config(sdla_t* card) | ||
| 2206 | { | ||
| 2207 | |||
| 2208 | ASY_CONFIGURATION_STRUCT cfg; | ||
| 2209 | CHDLC_MAILBOX_STRUCT *mailbox = card->mbox; | ||
| 2210 | int err; | ||
| 2211 | |||
| 2212 | memset(&cfg, 0, sizeof(ASY_CONFIGURATION_STRUCT)); | ||
| 2213 | |||
| 2214 | if(card->wandev.clocking) | ||
| 2215 | cfg.baud_rate = card->wandev.bps; | ||
| 2216 | |||
| 2217 | cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? | ||
| 2218 | INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; | ||
| 2219 | |||
| 2220 | cfg.modem_config_options = 0; | ||
| 2221 | cfg.asy_API_options = card->u.c.api_options; | ||
| 2222 | cfg.asy_protocol_options = card->u.c.protocol_options; | ||
| 2223 | cfg.Tx_bits_per_char = card->u.c.tx_bits_per_char; | ||
| 2224 | cfg.Rx_bits_per_char = card->u.c.rx_bits_per_char; | ||
| 2225 | cfg.stop_bits = card->u.c.stop_bits; | ||
| 2226 | cfg.parity = card->u.c.parity; | ||
| 2227 | cfg.break_timer = card->u.c.break_timer; | ||
| 2228 | cfg.asy_Rx_inter_char_timer = card->u.c.inter_char_timer; | ||
| 2229 | cfg.asy_Rx_complete_length = card->u.c.rx_complete_length; | ||
| 2230 | cfg.XON_char = card->u.c.xon_char; | ||
| 2231 | cfg.XOFF_char = card->u.c.xoff_char; | ||
| 2232 | cfg.asy_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | | ||
| 2233 | CHDLC_RX_DATA_BYTE_COUNT_STAT); | ||
| 2234 | |||
| 2235 | mailbox->buffer_length = sizeof(ASY_CONFIGURATION_STRUCT); | ||
| 2236 | memcpy(mailbox->data, &cfg, mailbox->buffer_length); | ||
| 2237 | mailbox->command = SET_ASY_CONFIGURATION; | ||
| 2238 | err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT; | ||
| 2239 | if (err != COMMAND_OK) | ||
| 2240 | chdlc_error (card, err, mailbox); | ||
| 2241 | return err; | ||
| 2242 | } | ||
| 2243 | |||
| 2244 | /*============================================================================ | ||
| 2245 | * Enable asynchronous communications. | ||
| 2246 | */ | ||
| 2247 | |||
| 2248 | static int asy_comm_enable (sdla_t* card) | ||
| 2249 | { | ||
| 2250 | |||
| 2251 | int err; | ||
| 2252 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
| 2253 | |||
| 2254 | mb->buffer_length = 0; | ||
| 2255 | mb->command = ENABLE_ASY_COMMUNICATIONS; | ||
| 2256 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 2257 | if (err != COMMAND_OK && card->wandev.dev) | ||
| 2258 | chdlc_error(card, err, mb); | ||
| 2259 | |||
| 2260 | if (!err) | ||
| 2261 | card->u.c.comm_enabled = 1; | ||
| 2262 | |||
| 2263 | return err; | ||
| 2264 | } | ||
| 2265 | |||
| 2266 | /*============================================================================ | ||
| 2267 | * Process global exception condition | ||
| 2268 | */ | ||
| 2269 | static int process_global_exception(sdla_t *card) | ||
| 2270 | { | ||
| 2271 | CHDLC_MAILBOX_STRUCT* mbox = card->mbox; | ||
| 2272 | int err; | ||
| 2273 | |||
| 2274 | mbox->buffer_length = 0; | ||
| 2275 | mbox->command = READ_GLOBAL_EXCEPTION_CONDITION; | ||
| 2276 | err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; | ||
| 2277 | |||
| 2278 | if(err != CMD_TIMEOUT ){ | ||
| 2279 | |||
| 2280 | switch(mbox->return_code) { | ||
| 2281 | |||
| 2282 | case EXCEP_MODEM_STATUS_CHANGE: | ||
| 2283 | |||
| 2284 | printk(KERN_INFO "%s: Modem status change\n", | ||
| 2285 | card->devname); | ||
| 2286 | |||
| 2287 | switch(mbox->data[0] & (DCD_HIGH | CTS_HIGH)) { | ||
| 2288 | case (DCD_HIGH): | ||
| 2289 | printk(KERN_INFO "%s: DCD high, CTS low\n",card->devname); | ||
| 2290 | break; | ||
| 2291 | case (CTS_HIGH): | ||
| 2292 | printk(KERN_INFO "%s: DCD low, CTS high\n",card->devname); | ||
| 2293 | break; | ||
| 2294 | case ((DCD_HIGH | CTS_HIGH)): | ||
| 2295 | printk(KERN_INFO "%s: DCD high, CTS high\n",card->devname); | ||
| 2296 | break; | ||
| 2297 | default: | ||
| 2298 | printk(KERN_INFO "%s: DCD low, CTS low\n",card->devname); | ||
| 2299 | break; | ||
| 2300 | } | ||
| 2301 | break; | ||
| 2302 | |||
| 2303 | case EXCEP_TRC_DISABLED: | ||
| 2304 | printk(KERN_INFO "%s: Line trace disabled\n", | ||
| 2305 | card->devname); | ||
| 2306 | break; | ||
| 2307 | |||
| 2308 | case EXCEP_IRQ_TIMEOUT: | ||
| 2309 | printk(KERN_INFO "%s: IRQ timeout occurred\n", | ||
| 2310 | card->devname); | ||
| 2311 | break; | ||
| 2312 | |||
| 2313 | case 0x17: | ||
| 2314 | if (card->tty_opt){ | ||
| 2315 | if (card->tty && card->tty_open){ | ||
| 2316 | printk(KERN_INFO | ||
| 2317 | "%s: Modem Hangup Exception: Hanging Up!\n", | ||
| 2318 | card->devname); | ||
| 2319 | tty_hangup(card->tty); | ||
| 2320 | } | ||
| 2321 | break; | ||
| 2322 | } | ||
| 2323 | |||
| 2324 | /* If TTY is not used just drop throught */ | ||
| 2325 | |||
| 2326 | default: | ||
| 2327 | printk(KERN_INFO "%s: Global exception %x\n", | ||
| 2328 | card->devname, mbox->return_code); | ||
| 2329 | break; | ||
| 2330 | } | ||
| 2331 | } | ||
| 2332 | return 0; | ||
| 2333 | } | ||
| 2334 | |||
| 2335 | |||
| 2336 | /*============================================================================ | ||
| 2337 | * Process chdlc exception condition | ||
| 2338 | */ | ||
| 2339 | static int process_chdlc_exception(sdla_t *card) | ||
| 2340 | { | ||
| 2341 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
| 2342 | int err; | ||
| 2343 | |||
| 2344 | mb->buffer_length = 0; | ||
| 2345 | mb->command = READ_CHDLC_EXCEPTION_CONDITION; | ||
| 2346 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 2347 | if(err != CMD_TIMEOUT) { | ||
| 2348 | |||
| 2349 | switch (err) { | ||
| 2350 | |||
| 2351 | case EXCEP_LINK_ACTIVE: | ||
| 2352 | port_set_state(card, WAN_CONNECTED); | ||
| 2353 | trigger_chdlc_poll(card->wandev.dev); | ||
| 2354 | break; | ||
| 2355 | |||
| 2356 | case EXCEP_LINK_INACTIVE_MODEM: | ||
| 2357 | port_set_state(card, WAN_DISCONNECTED); | ||
| 2358 | unconfigure_ip(card); | ||
| 2359 | trigger_chdlc_poll(card->wandev.dev); | ||
| 2360 | break; | ||
| 2361 | |||
| 2362 | case EXCEP_LINK_INACTIVE_KPALV: | ||
| 2363 | port_set_state(card, WAN_DISCONNECTED); | ||
| 2364 | printk(KERN_INFO "%s: Keepalive timer expired.\n", | ||
| 2365 | card->devname); | ||
| 2366 | unconfigure_ip(card); | ||
| 2367 | trigger_chdlc_poll(card->wandev.dev); | ||
| 2368 | break; | ||
| 2369 | |||
| 2370 | case EXCEP_IP_ADDRESS_DISCOVERED: | ||
| 2371 | if (configure_ip(card)) | ||
| 2372 | return -1; | ||
| 2373 | break; | ||
| 2374 | |||
| 2375 | case EXCEP_LOOPBACK_CONDITION: | ||
| 2376 | printk(KERN_INFO "%s: Loopback Condition Detected.\n", | ||
| 2377 | card->devname); | ||
| 2378 | break; | ||
| 2379 | |||
| 2380 | case NO_CHDLC_EXCEP_COND_TO_REPORT: | ||
| 2381 | printk(KERN_INFO "%s: No exceptions reported.\n", | ||
| 2382 | card->devname); | ||
| 2383 | break; | ||
| 2384 | } | ||
| 2385 | |||
| 2386 | } | ||
| 2387 | return 0; | ||
| 2388 | } | ||
| 2389 | |||
| 2390 | |||
| 2391 | /*============================================================================ | ||
| 2392 | * Configure IP from SLARP negotiation | ||
| 2393 | * This adds dynamic routes when SLARP has provided valid addresses | ||
| 2394 | */ | ||
| 2395 | |||
| 2396 | static int configure_ip (sdla_t* card) | ||
| 2397 | { | ||
| 2398 | struct net_device *dev = card->wandev.dev; | ||
| 2399 | chdlc_private_area_t *chdlc_priv_area; | ||
| 2400 | char err; | ||
| 2401 | |||
| 2402 | if (!dev) | ||
| 2403 | return 0; | ||
| 2404 | |||
| 2405 | chdlc_priv_area = dev->priv; | ||
| 2406 | |||
| 2407 | |||
| 2408 | /* set to discover */ | ||
| 2409 | if(card->u.c.slarp_timer != 0x00) { | ||
| 2410 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
| 2411 | CHDLC_CONFIGURATION_STRUCT *cfg; | ||
| 2412 | |||
| 2413 | mb->buffer_length = 0; | ||
| 2414 | mb->command = READ_CHDLC_CONFIGURATION; | ||
| 2415 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 2416 | |||
| 2417 | if(err != COMMAND_OK) { | ||
| 2418 | chdlc_error(card,err,mb); | ||
| 2419 | return -1; | ||
| 2420 | } | ||
| 2421 | |||
| 2422 | cfg = (CHDLC_CONFIGURATION_STRUCT *)mb->data; | ||
| 2423 | chdlc_priv_area->IP_address = cfg->IP_address; | ||
| 2424 | chdlc_priv_area->IP_netmask = cfg->IP_netmask; | ||
| 2425 | |||
| 2426 | /* Set flag to add route */ | ||
| 2427 | chdlc_priv_area->route_status = ADD_ROUTE; | ||
| 2428 | |||
| 2429 | /* The idea here is to add the route in the poll routine. | ||
| 2430 | This way, we aren't in interrupt context when adding routes */ | ||
| 2431 | trigger_chdlc_poll(dev); | ||
| 2432 | } | ||
| 2433 | |||
| 2434 | return 0; | ||
| 2435 | } | ||
| 2436 | |||
| 2437 | |||
| 2438 | /*============================================================================ | ||
| 2439 | * Un-Configure IP negotiated by SLARP | ||
| 2440 | * This removes dynamic routes when the link becomes inactive. | ||
| 2441 | */ | ||
| 2442 | |||
| 2443 | static int unconfigure_ip (sdla_t* card) | ||
| 2444 | { | ||
| 2445 | struct net_device *dev = card->wandev.dev; | ||
| 2446 | chdlc_private_area_t *chdlc_priv_area; | ||
| 2447 | |||
| 2448 | if (!dev) | ||
| 2449 | return 0; | ||
| 2450 | |||
| 2451 | chdlc_priv_area= dev->priv; | ||
| 2452 | |||
| 2453 | if (chdlc_priv_area->route_status == ROUTE_ADDED) { | ||
| 2454 | |||
| 2455 | /* Note: If this function is called, the | ||
| 2456 | * port state has been DISCONNECTED. This state | ||
| 2457 | * change will trigger a poll_disconnected | ||
| 2458 | * function, that will check for this condition. | ||
| 2459 | */ | ||
| 2460 | chdlc_priv_area->route_status = REMOVE_ROUTE; | ||
| 2461 | |||
| 2462 | } | ||
| 2463 | return 0; | ||
| 2464 | } | ||
| 2465 | |||
| 2466 | /*============================================================================ | ||
| 2467 | * Routine to add/remove routes | ||
| 2468 | * Called like a polling routine when Routes are flagged to be added/removed. | ||
| 2469 | */ | ||
| 2470 | |||
| 2471 | static void process_route (sdla_t *card) | ||
| 2472 | { | ||
| 2473 | struct net_device *dev = card->wandev.dev; | ||
| 2474 | unsigned char port_num; | ||
| 2475 | chdlc_private_area_t *chdlc_priv_area = NULL; | ||
| 2476 | u32 local_IP_addr = 0; | ||
| 2477 | u32 remote_IP_addr = 0; | ||
| 2478 | u32 IP_netmask, IP_addr; | ||
| 2479 | int err = 0; | ||
| 2480 | struct in_device *in_dev; | ||
| 2481 | mm_segment_t fs; | ||
| 2482 | struct ifreq if_info; | ||
| 2483 | struct sockaddr_in *if_data1, *if_data2; | ||
| 2484 | |||
| 2485 | chdlc_priv_area = dev->priv; | ||
| 2486 | port_num = card->u.c.comm_port; | ||
| 2487 | |||
| 2488 | /* Bug Fix Mar 16 2000 | ||
| 2489 | * AND the IP address to the Mask before checking | ||
| 2490 | * the last two bits. */ | ||
| 2491 | |||
| 2492 | if((chdlc_priv_area->route_status == ADD_ROUTE) && | ||
| 2493 | ((chdlc_priv_area->IP_address & ~chdlc_priv_area->IP_netmask) > 2)) { | ||
| 2494 | |||
| 2495 | printk(KERN_INFO "%s: Dynamic route failure.\n",card->devname); | ||
| 2496 | |||
| 2497 | if(card->u.c.slarp_timer) { | ||
| 2498 | u32 addr_net = htonl(chdlc_priv_area->IP_address); | ||
| 2499 | |||
| 2500 | printk(KERN_INFO "%s: Bad IP address %u.%u.%u.%u received\n", | ||
| 2501 | card->devname, | ||
| 2502 | NIPQUAD(addr_net)); | ||
| 2503 | printk(KERN_INFO "%s: from remote station.\n", | ||
| 2504 | card->devname); | ||
| 2505 | |||
| 2506 | }else{ | ||
| 2507 | u32 addr_net = htonl(chdlc_priv_area->IP_address); | ||
| 2508 | |||
| 2509 | printk(KERN_INFO "%s: Bad IP address %u.%u.%u.%u issued\n", | ||
| 2510 | card->devname, | ||
| 2511 | NIPQUAD(addr_net)); | ||
| 2512 | printk(KERN_INFO "%s: to remote station. Local\n", | ||
| 2513 | card->devname); | ||
| 2514 | printk(KERN_INFO "%s: IP address must be A.B.C.1\n", | ||
| 2515 | card->devname); | ||
| 2516 | printk(KERN_INFO "%s: or A.B.C.2.\n",card->devname); | ||
| 2517 | } | ||
| 2518 | |||
| 2519 | /* remove the route due to the IP address error condition */ | ||
| 2520 | chdlc_priv_area->route_status = REMOVE_ROUTE; | ||
| 2521 | err = 1; | ||
| 2522 | } | ||
| 2523 | |||
| 2524 | /* If we are removing a route with bad IP addressing, then use the */ | ||
| 2525 | /* locally configured IP addresses */ | ||
| 2526 | if((chdlc_priv_area->route_status == REMOVE_ROUTE) && err) { | ||
| 2527 | |||
| 2528 | /* do not remove a bad route that has already been removed */ | ||
| 2529 | if(chdlc_priv_area->route_removed) { | ||
| 2530 | return; | ||
| 2531 | } | ||
| 2532 | |||
| 2533 | in_dev = dev->ip_ptr; | ||
| 2534 | |||
| 2535 | if(in_dev != NULL) { | ||
| 2536 | struct in_ifaddr *ifa = in_dev->ifa_list; | ||
| 2537 | if (ifa != NULL ) { | ||
| 2538 | local_IP_addr = ifa->ifa_local; | ||
| 2539 | IP_netmask = ifa->ifa_mask; | ||
| 2540 | } | ||
| 2541 | } | ||
| 2542 | }else{ | ||
| 2543 | /* According to Cisco HDLC, if the point-to-point address is | ||
| 2544 | A.B.C.1, then we are the opposite (A.B.C.2), and vice-versa. | ||
| 2545 | */ | ||
| 2546 | IP_netmask = ntohl(chdlc_priv_area->IP_netmask); | ||
| 2547 | remote_IP_addr = ntohl(chdlc_priv_area->IP_address); | ||
| 2548 | |||
| 2549 | |||
| 2550 | /* If Netmask is 255.255.255.255 the local address | ||
| 2551 | * calculation will fail. Default it back to 255.255.255.0 */ | ||
| 2552 | if (IP_netmask == 0xffffffff) | ||
| 2553 | IP_netmask &= 0x00ffffff; | ||
| 2554 | |||
| 2555 | /* Bug Fix Mar 16 2000 | ||
| 2556 | * AND the Remote IP address with IP netmask, instead | ||
| 2557 | * of static netmask of 255.255.255.0 */ | ||
| 2558 | local_IP_addr = (remote_IP_addr & IP_netmask) + | ||
| 2559 | (~remote_IP_addr & ntohl(0x0003)); | ||
| 2560 | |||
| 2561 | if(!card->u.c.slarp_timer) { | ||
| 2562 | IP_addr = local_IP_addr; | ||
| 2563 | local_IP_addr = remote_IP_addr; | ||
| 2564 | remote_IP_addr = IP_addr; | ||
| 2565 | } | ||
| 2566 | } | ||
| 2567 | |||
| 2568 | fs = get_fs(); /* Save file system */ | ||
| 2569 | set_fs(get_ds()); /* Get user space block */ | ||
| 2570 | |||
| 2571 | /* Setup a structure for adding/removing routes */ | ||
| 2572 | memset(&if_info, 0, sizeof(if_info)); | ||
| 2573 | strcpy(if_info.ifr_name, dev->name); | ||
| 2574 | |||
| 2575 | switch (chdlc_priv_area->route_status) { | ||
| 2576 | |||
| 2577 | case ADD_ROUTE: | ||
| 2578 | |||
| 2579 | if(!card->u.c.slarp_timer) { | ||
| 2580 | if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; | ||
| 2581 | if_data2->sin_addr.s_addr = remote_IP_addr; | ||
| 2582 | if_data2->sin_family = AF_INET; | ||
| 2583 | err = devinet_ioctl(SIOCSIFDSTADDR, &if_info); | ||
| 2584 | } else { | ||
| 2585 | if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; | ||
| 2586 | if_data1->sin_addr.s_addr = local_IP_addr; | ||
| 2587 | if_data1->sin_family = AF_INET; | ||
| 2588 | if(!(err = devinet_ioctl(SIOCSIFADDR, &if_info))){ | ||
| 2589 | if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; | ||
| 2590 | if_data2->sin_addr.s_addr = remote_IP_addr; | ||
| 2591 | if_data2->sin_family = AF_INET; | ||
| 2592 | err = devinet_ioctl(SIOCSIFDSTADDR, &if_info); | ||
| 2593 | } | ||
| 2594 | } | ||
| 2595 | |||
| 2596 | if(err) { | ||
| 2597 | printk(KERN_INFO "%s: Add route %u.%u.%u.%u failed (%d)\n", | ||
| 2598 | card->devname, NIPQUAD(remote_IP_addr), err); | ||
| 2599 | } else { | ||
| 2600 | ((chdlc_private_area_t *)dev->priv)->route_status = ROUTE_ADDED; | ||
| 2601 | printk(KERN_INFO "%s: Dynamic route added.\n", | ||
| 2602 | card->devname); | ||
| 2603 | printk(KERN_INFO "%s: Local IP addr : %u.%u.%u.%u\n", | ||
| 2604 | card->devname, NIPQUAD(local_IP_addr)); | ||
| 2605 | printk(KERN_INFO "%s: Remote IP addr: %u.%u.%u.%u\n", | ||
| 2606 | card->devname, NIPQUAD(remote_IP_addr)); | ||
| 2607 | chdlc_priv_area->route_removed = 0; | ||
| 2608 | } | ||
| 2609 | break; | ||
| 2610 | |||
| 2611 | |||
| 2612 | case REMOVE_ROUTE: | ||
| 2613 | |||
| 2614 | /* Change the local ip address of the interface to 0. | ||
| 2615 | * This will also delete the destination route. | ||
| 2616 | */ | ||
| 2617 | if(!card->u.c.slarp_timer) { | ||
| 2618 | if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; | ||
| 2619 | if_data2->sin_addr.s_addr = 0; | ||
| 2620 | if_data2->sin_family = AF_INET; | ||
| 2621 | err = devinet_ioctl(SIOCSIFDSTADDR, &if_info); | ||
| 2622 | } else { | ||
| 2623 | if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; | ||
| 2624 | if_data1->sin_addr.s_addr = 0; | ||
| 2625 | if_data1->sin_family = AF_INET; | ||
| 2626 | err = devinet_ioctl(SIOCSIFADDR,&if_info); | ||
| 2627 | |||
| 2628 | } | ||
| 2629 | if(err) { | ||
| 2630 | printk(KERN_INFO | ||
| 2631 | "%s: Remove route %u.%u.%u.%u failed, (err %d)\n", | ||
| 2632 | card->devname, NIPQUAD(remote_IP_addr), | ||
| 2633 | err); | ||
| 2634 | } else { | ||
| 2635 | ((chdlc_private_area_t *)dev->priv)->route_status = | ||
| 2636 | NO_ROUTE; | ||
| 2637 | printk(KERN_INFO "%s: Dynamic route removed: %u.%u.%u.%u\n", | ||
| 2638 | card->devname, NIPQUAD(local_IP_addr)); | ||
| 2639 | chdlc_priv_area->route_removed = 1; | ||
| 2640 | } | ||
| 2641 | break; | ||
| 2642 | } | ||
| 2643 | |||
| 2644 | set_fs(fs); /* Restore file system */ | ||
| 2645 | |||
| 2646 | } | ||
| 2647 | |||
| 2648 | |||
| 2649 | /*============================================================================= | ||
| 2650 | * Store a UDP management packet for later processing. | ||
| 2651 | */ | ||
| 2652 | |||
| 2653 | static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, | ||
| 2654 | struct sk_buff *skb, struct net_device* dev, | ||
| 2655 | chdlc_private_area_t* chdlc_priv_area) | ||
| 2656 | { | ||
| 2657 | int udp_pkt_stored = 0; | ||
| 2658 | |||
| 2659 | if(!chdlc_priv_area->udp_pkt_lgth && | ||
| 2660 | (skb->len <= MAX_LGTH_UDP_MGNT_PKT)) { | ||
| 2661 | chdlc_priv_area->udp_pkt_lgth = skb->len; | ||
| 2662 | chdlc_priv_area->udp_pkt_src = udp_pkt_src; | ||
| 2663 | memcpy(chdlc_priv_area->udp_pkt_data, skb->data, skb->len); | ||
| 2664 | chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UDP; | ||
| 2665 | udp_pkt_stored = 1; | ||
| 2666 | } | ||
| 2667 | |||
| 2668 | if(udp_pkt_src == UDP_PKT_FRM_STACK){ | ||
| 2669 | dev_kfree_skb_any(skb); | ||
| 2670 | }else{ | ||
| 2671 | dev_kfree_skb_any(skb); | ||
| 2672 | } | ||
| 2673 | |||
| 2674 | return(udp_pkt_stored); | ||
| 2675 | } | ||
| 2676 | |||
| 2677 | |||
| 2678 | /*============================================================================= | ||
| 2679 | * Process UDP management packet. | ||
| 2680 | */ | ||
| 2681 | |||
| 2682 | static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, | ||
| 2683 | chdlc_private_area_t* chdlc_priv_area ) | ||
| 2684 | { | ||
| 2685 | unsigned char *buf; | ||
| 2686 | unsigned int frames, len; | ||
| 2687 | struct sk_buff *new_skb; | ||
| 2688 | unsigned short buffer_length, real_len; | ||
| 2689 | unsigned long data_ptr; | ||
| 2690 | unsigned data_length; | ||
| 2691 | int udp_mgmt_req_valid = 1; | ||
| 2692 | CHDLC_MAILBOX_STRUCT *mb = card->mbox; | ||
| 2693 | SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; | ||
| 2694 | chdlc_udp_pkt_t *chdlc_udp_pkt; | ||
| 2695 | struct timeval tv; | ||
| 2696 | int err; | ||
| 2697 | char ut_char; | ||
| 2698 | |||
| 2699 | chdlc_udp_pkt = (chdlc_udp_pkt_t *) chdlc_priv_area->udp_pkt_data; | ||
| 2700 | |||
| 2701 | if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK){ | ||
| 2702 | |||
| 2703 | /* Only these commands are support for remote debugging. | ||
| 2704 | * All others are not */ | ||
| 2705 | switch(chdlc_udp_pkt->cblock.command) { | ||
| 2706 | |||
| 2707 | case READ_GLOBAL_STATISTICS: | ||
| 2708 | case READ_MODEM_STATUS: | ||
| 2709 | case READ_CHDLC_LINK_STATUS: | ||
| 2710 | case CPIPE_ROUTER_UP_TIME: | ||
| 2711 | case READ_COMMS_ERROR_STATS: | ||
| 2712 | case READ_CHDLC_OPERATIONAL_STATS: | ||
| 2713 | |||
| 2714 | /* These two commands are executed for | ||
| 2715 | * each request */ | ||
| 2716 | case READ_CHDLC_CONFIGURATION: | ||
| 2717 | case READ_CHDLC_CODE_VERSION: | ||
| 2718 | udp_mgmt_req_valid = 1; | ||
| 2719 | break; | ||
| 2720 | default: | ||
| 2721 | udp_mgmt_req_valid = 0; | ||
| 2722 | break; | ||
| 2723 | } | ||
| 2724 | } | ||
| 2725 | |||
| 2726 | if(!udp_mgmt_req_valid) { | ||
| 2727 | |||
| 2728 | /* set length to 0 */ | ||
| 2729 | chdlc_udp_pkt->cblock.buffer_length = 0; | ||
| 2730 | |||
| 2731 | /* set return code */ | ||
| 2732 | chdlc_udp_pkt->cblock.return_code = 0xCD; | ||
| 2733 | |||
| 2734 | if (net_ratelimit()){ | ||
| 2735 | printk(KERN_INFO | ||
| 2736 | "%s: Warning, Illegal UDP command attempted from network: %x\n", | ||
| 2737 | card->devname,chdlc_udp_pkt->cblock.command); | ||
| 2738 | } | ||
| 2739 | |||
| 2740 | } else { | ||
| 2741 | unsigned long trace_status_cfg_addr = 0; | ||
| 2742 | TRACE_STATUS_EL_CFG_STRUCT trace_cfg_struct; | ||
| 2743 | TRACE_STATUS_ELEMENT_STRUCT trace_element_struct; | ||
| 2744 | |||
| 2745 | switch(chdlc_udp_pkt->cblock.command) { | ||
| 2746 | |||
| 2747 | case CPIPE_ENABLE_TRACING: | ||
| 2748 | if (!chdlc_priv_area->TracingEnabled) { | ||
| 2749 | |||
| 2750 | /* OPERATE_DATALINE_MONITOR */ | ||
| 2751 | |||
| 2752 | mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); | ||
| 2753 | mb->command = SET_TRACE_CONFIGURATION; | ||
| 2754 | |||
| 2755 | ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> | ||
| 2756 | trace_config = TRACE_ACTIVE; | ||
| 2757 | /* Trace delay mode is not used because it slows | ||
| 2758 | down transfer and results in a standoff situation | ||
| 2759 | when there is a lot of data */ | ||
| 2760 | |||
| 2761 | /* Configure the Trace based on user inputs */ | ||
| 2762 | ((LINE_TRACE_CONFIG_STRUCT *)mb->data)->trace_config |= | ||
| 2763 | chdlc_udp_pkt->data[0]; | ||
| 2764 | |||
| 2765 | ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> | ||
| 2766 | trace_deactivation_timer = 4000; | ||
| 2767 | |||
| 2768 | |||
| 2769 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 2770 | if (err != COMMAND_OK) { | ||
| 2771 | chdlc_error(card,err,mb); | ||
| 2772 | card->TracingEnabled = 0; | ||
| 2773 | chdlc_udp_pkt->cblock.return_code = err; | ||
| 2774 | mb->buffer_length = 0; | ||
| 2775 | break; | ||
| 2776 | } | ||
| 2777 | |||
| 2778 | /* Get the base address of the trace element list */ | ||
| 2779 | mb->buffer_length = 0; | ||
| 2780 | mb->command = READ_TRACE_CONFIGURATION; | ||
| 2781 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 2782 | |||
| 2783 | if (err != COMMAND_OK) { | ||
| 2784 | chdlc_error(card,err,mb); | ||
| 2785 | chdlc_priv_area->TracingEnabled = 0; | ||
| 2786 | chdlc_udp_pkt->cblock.return_code = err; | ||
| 2787 | mb->buffer_length = 0; | ||
| 2788 | break; | ||
| 2789 | } | ||
| 2790 | |||
| 2791 | trace_status_cfg_addr =((LINE_TRACE_CONFIG_STRUCT *) | ||
| 2792 | mb->data) -> ptr_trace_stat_el_cfg_struct; | ||
| 2793 | |||
| 2794 | sdla_peek(&card->hw, trace_status_cfg_addr, | ||
| 2795 | &trace_cfg_struct, sizeof(trace_cfg_struct)); | ||
| 2796 | |||
| 2797 | chdlc_priv_area->start_trace_addr = trace_cfg_struct. | ||
| 2798 | base_addr_trace_status_elements; | ||
| 2799 | |||
| 2800 | chdlc_priv_area->number_trace_elements = | ||
| 2801 | trace_cfg_struct.number_trace_status_elements; | ||
| 2802 | |||
| 2803 | chdlc_priv_area->end_trace_addr = (unsigned long) | ||
| 2804 | ((TRACE_STATUS_ELEMENT_STRUCT *) | ||
| 2805 | chdlc_priv_area->start_trace_addr + | ||
| 2806 | (chdlc_priv_area->number_trace_elements - 1)); | ||
| 2807 | |||
| 2808 | chdlc_priv_area->base_addr_trace_buffer = | ||
| 2809 | trace_cfg_struct.base_addr_trace_buffer; | ||
| 2810 | |||
| 2811 | chdlc_priv_area->end_addr_trace_buffer = | ||
| 2812 | trace_cfg_struct.end_addr_trace_buffer; | ||
| 2813 | |||
| 2814 | chdlc_priv_area->curr_trace_addr = | ||
| 2815 | trace_cfg_struct.next_trace_element_to_use; | ||
| 2816 | |||
| 2817 | chdlc_priv_area->available_buffer_space = 2000 - | ||
| 2818 | sizeof(ip_pkt_t) - | ||
| 2819 | sizeof(udp_pkt_t) - | ||
| 2820 | sizeof(wp_mgmt_t) - | ||
| 2821 | sizeof(cblock_t) - | ||
| 2822 | sizeof(trace_info_t); | ||
| 2823 | } | ||
| 2824 | chdlc_udp_pkt->cblock.return_code = COMMAND_OK; | ||
| 2825 | mb->buffer_length = 0; | ||
| 2826 | chdlc_priv_area->TracingEnabled = 1; | ||
| 2827 | break; | ||
| 2828 | |||
| 2829 | |||
| 2830 | case CPIPE_DISABLE_TRACING: | ||
| 2831 | if (chdlc_priv_area->TracingEnabled) { | ||
| 2832 | |||
| 2833 | /* OPERATE_DATALINE_MONITOR */ | ||
| 2834 | mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); | ||
| 2835 | mb->command = SET_TRACE_CONFIGURATION; | ||
| 2836 | ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> | ||
| 2837 | trace_config = TRACE_INACTIVE; | ||
| 2838 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 2839 | } | ||
| 2840 | |||
| 2841 | chdlc_priv_area->TracingEnabled = 0; | ||
| 2842 | chdlc_udp_pkt->cblock.return_code = COMMAND_OK; | ||
| 2843 | mb->buffer_length = 0; | ||
| 2844 | break; | ||
| 2845 | |||
| 2846 | |||
| 2847 | case CPIPE_GET_TRACE_INFO: | ||
| 2848 | |||
| 2849 | if (!chdlc_priv_area->TracingEnabled) { | ||
| 2850 | chdlc_udp_pkt->cblock.return_code = 1; | ||
| 2851 | mb->buffer_length = 0; | ||
| 2852 | break; | ||
| 2853 | } | ||
| 2854 | |||
| 2855 | chdlc_udp_pkt->trace_info.ismoredata = 0x00; | ||
| 2856 | buffer_length = 0; /* offset of packet already occupied */ | ||
| 2857 | |||
| 2858 | for (frames=0; frames < chdlc_priv_area->number_trace_elements; frames++){ | ||
| 2859 | |||
| 2860 | trace_pkt_t *trace_pkt = (trace_pkt_t *) | ||
| 2861 | &chdlc_udp_pkt->data[buffer_length]; | ||
| 2862 | |||
| 2863 | sdla_peek(&card->hw, chdlc_priv_area->curr_trace_addr, | ||
| 2864 | (unsigned char *)&trace_element_struct, | ||
| 2865 | sizeof(TRACE_STATUS_ELEMENT_STRUCT)); | ||
| 2866 | |||
| 2867 | if (trace_element_struct.opp_flag == 0x00) { | ||
| 2868 | break; | ||
| 2869 | } | ||
| 2870 | |||
| 2871 | /* get pointer to real data */ | ||
| 2872 | data_ptr = trace_element_struct.ptr_data_bfr; | ||
| 2873 | |||
| 2874 | /* See if there is actual data on the trace buffer */ | ||
| 2875 | if (data_ptr){ | ||
| 2876 | data_length = trace_element_struct.trace_length; | ||
| 2877 | }else{ | ||
| 2878 | data_length = 0; | ||
| 2879 | chdlc_udp_pkt->trace_info.ismoredata = 0x01; | ||
| 2880 | } | ||
| 2881 | |||
| 2882 | if( (chdlc_priv_area->available_buffer_space - buffer_length) | ||
| 2883 | < ( sizeof(trace_pkt_t) + data_length) ) { | ||
| 2884 | |||
| 2885 | /* indicate there are more frames on board & exit */ | ||
| 2886 | chdlc_udp_pkt->trace_info.ismoredata = 0x01; | ||
| 2887 | break; | ||
| 2888 | } | ||
| 2889 | |||
| 2890 | trace_pkt->status = trace_element_struct.trace_type; | ||
| 2891 | |||
| 2892 | trace_pkt->time_stamp = | ||
| 2893 | trace_element_struct.trace_time_stamp; | ||
| 2894 | |||
| 2895 | trace_pkt->real_length = | ||
| 2896 | trace_element_struct.trace_length; | ||
| 2897 | |||
| 2898 | /* see if we can fit the frame into the user buffer */ | ||
| 2899 | real_len = trace_pkt->real_length; | ||
| 2900 | |||
| 2901 | if (data_ptr == 0) { | ||
| 2902 | trace_pkt->data_avail = 0x00; | ||
| 2903 | } else { | ||
| 2904 | unsigned tmp = 0; | ||
| 2905 | |||
| 2906 | /* get the data from circular buffer | ||
| 2907 | must check for end of buffer */ | ||
| 2908 | trace_pkt->data_avail = 0x01; | ||
| 2909 | |||
| 2910 | if ((data_ptr + real_len) > | ||
| 2911 | chdlc_priv_area->end_addr_trace_buffer + 1){ | ||
| 2912 | |||
| 2913 | tmp = chdlc_priv_area->end_addr_trace_buffer - data_ptr + 1; | ||
| 2914 | sdla_peek(&card->hw, data_ptr, | ||
| 2915 | trace_pkt->data,tmp); | ||
| 2916 | data_ptr = chdlc_priv_area->base_addr_trace_buffer; | ||
| 2917 | } | ||
| 2918 | |||
| 2919 | sdla_peek(&card->hw, data_ptr, | ||
| 2920 | &trace_pkt->data[tmp], real_len - tmp); | ||
| 2921 | } | ||
| 2922 | |||
| 2923 | /* zero the opp flag to show we got the frame */ | ||
| 2924 | ut_char = 0x00; | ||
| 2925 | sdla_poke(&card->hw, chdlc_priv_area->curr_trace_addr, &ut_char, 1); | ||
| 2926 | |||
| 2927 | /* now move onto the next frame */ | ||
| 2928 | chdlc_priv_area->curr_trace_addr += sizeof(TRACE_STATUS_ELEMENT_STRUCT); | ||
| 2929 | |||
| 2930 | /* check if we went over the last address */ | ||
| 2931 | if ( chdlc_priv_area->curr_trace_addr > chdlc_priv_area->end_trace_addr ) { | ||
| 2932 | chdlc_priv_area->curr_trace_addr = chdlc_priv_area->start_trace_addr; | ||
| 2933 | } | ||
| 2934 | |||
| 2935 | if(trace_pkt->data_avail == 0x01) { | ||
| 2936 | buffer_length += real_len - 1; | ||
| 2937 | } | ||
| 2938 | |||
| 2939 | /* for the header */ | ||
| 2940 | buffer_length += sizeof(trace_pkt_t); | ||
| 2941 | |||
| 2942 | } /* For Loop */ | ||
| 2943 | |||
| 2944 | if (frames == chdlc_priv_area->number_trace_elements){ | ||
| 2945 | chdlc_udp_pkt->trace_info.ismoredata = 0x01; | ||
| 2946 | } | ||
| 2947 | chdlc_udp_pkt->trace_info.num_frames = frames; | ||
| 2948 | |||
| 2949 | mb->buffer_length = buffer_length; | ||
| 2950 | chdlc_udp_pkt->cblock.buffer_length = buffer_length; | ||
| 2951 | |||
| 2952 | chdlc_udp_pkt->cblock.return_code = COMMAND_OK; | ||
| 2953 | |||
| 2954 | break; | ||
| 2955 | |||
| 2956 | |||
| 2957 | case CPIPE_FT1_READ_STATUS: | ||
| 2958 | ((unsigned char *)chdlc_udp_pkt->data )[0] = | ||
| 2959 | flags->FT1_info_struct.parallel_port_A_input; | ||
| 2960 | |||
| 2961 | ((unsigned char *)chdlc_udp_pkt->data )[1] = | ||
| 2962 | flags->FT1_info_struct.parallel_port_B_input; | ||
| 2963 | |||
| 2964 | chdlc_udp_pkt->cblock.return_code = COMMAND_OK; | ||
| 2965 | chdlc_udp_pkt->cblock.buffer_length = 2; | ||
| 2966 | mb->buffer_length = 2; | ||
| 2967 | break; | ||
| 2968 | |||
| 2969 | case CPIPE_ROUTER_UP_TIME: | ||
| 2970 | do_gettimeofday( &tv ); | ||
| 2971 | chdlc_priv_area->router_up_time = tv.tv_sec - | ||
| 2972 | chdlc_priv_area->router_start_time; | ||
| 2973 | *(unsigned long *)&chdlc_udp_pkt->data = | ||
| 2974 | chdlc_priv_area->router_up_time; | ||
| 2975 | mb->buffer_length = sizeof(unsigned long); | ||
| 2976 | chdlc_udp_pkt->cblock.buffer_length = sizeof(unsigned long); | ||
| 2977 | chdlc_udp_pkt->cblock.return_code = COMMAND_OK; | ||
| 2978 | break; | ||
| 2979 | |||
| 2980 | case FT1_MONITOR_STATUS_CTRL: | ||
| 2981 | /* Enable FT1 MONITOR STATUS */ | ||
| 2982 | if ((chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_STATUS) || | ||
| 2983 | (chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_OP_STATS)) { | ||
| 2984 | |||
| 2985 | if( rCount++ != 0 ) { | ||
| 2986 | chdlc_udp_pkt->cblock. | ||
| 2987 | return_code = COMMAND_OK; | ||
| 2988 | mb->buffer_length = 1; | ||
| 2989 | break; | ||
| 2990 | } | ||
| 2991 | } | ||
| 2992 | |||
| 2993 | /* Disable FT1 MONITOR STATUS */ | ||
| 2994 | if( chdlc_udp_pkt->data[0] == 0) { | ||
| 2995 | |||
| 2996 | if( --rCount != 0) { | ||
| 2997 | chdlc_udp_pkt->cblock. | ||
| 2998 | return_code = COMMAND_OK; | ||
| 2999 | mb->buffer_length = 1; | ||
| 3000 | break; | ||
| 3001 | } | ||
| 3002 | } | ||
| 3003 | goto dflt_1; | ||
| 3004 | |||
| 3005 | default: | ||
| 3006 | dflt_1: | ||
| 3007 | /* it's a board command */ | ||
| 3008 | mb->command = chdlc_udp_pkt->cblock.command; | ||
| 3009 | mb->buffer_length = chdlc_udp_pkt->cblock.buffer_length; | ||
| 3010 | if (mb->buffer_length) { | ||
| 3011 | memcpy(&mb->data, (unsigned char *) chdlc_udp_pkt-> | ||
| 3012 | data, mb->buffer_length); | ||
| 3013 | } | ||
| 3014 | /* run the command on the board */ | ||
| 3015 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 3016 | if (err != COMMAND_OK) { | ||
| 3017 | break; | ||
| 3018 | } | ||
| 3019 | |||
| 3020 | /* copy the result back to our buffer */ | ||
| 3021 | memcpy(&chdlc_udp_pkt->cblock, mb, sizeof(cblock_t)); | ||
| 3022 | |||
| 3023 | if (mb->buffer_length) { | ||
| 3024 | memcpy(&chdlc_udp_pkt->data, &mb->data, | ||
| 3025 | mb->buffer_length); | ||
| 3026 | } | ||
| 3027 | |||
| 3028 | } /* end of switch */ | ||
| 3029 | } /* end of else */ | ||
| 3030 | |||
| 3031 | /* Fill UDP TTL */ | ||
| 3032 | chdlc_udp_pkt->ip_pkt.ttl = card->wandev.ttl; | ||
| 3033 | |||
| 3034 | len = reply_udp(chdlc_priv_area->udp_pkt_data, mb->buffer_length); | ||
| 3035 | |||
| 3036 | |||
| 3037 | if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK){ | ||
| 3038 | |||
| 3039 | /* Must check if we interrupted if_send() routine. The | ||
| 3040 | * tx buffers might be used. If so drop the packet */ | ||
| 3041 | if (!test_bit(SEND_CRIT,&card->wandev.critical)) { | ||
| 3042 | |||
| 3043 | if(!chdlc_send(card, chdlc_priv_area->udp_pkt_data, len)) { | ||
| 3044 | ++ card->wandev.stats.tx_packets; | ||
| 3045 | card->wandev.stats.tx_bytes += len; | ||
| 3046 | } | ||
| 3047 | } | ||
| 3048 | } else { | ||
| 3049 | |||
| 3050 | /* Pass it up the stack | ||
| 3051 | Allocate socket buffer */ | ||
| 3052 | if ((new_skb = dev_alloc_skb(len)) != NULL) { | ||
| 3053 | /* copy data into new_skb */ | ||
| 3054 | |||
| 3055 | buf = skb_put(new_skb, len); | ||
| 3056 | memcpy(buf, chdlc_priv_area->udp_pkt_data, len); | ||
| 3057 | |||
| 3058 | /* Decapsulate pkt and pass it up the protocol stack */ | ||
| 3059 | new_skb->protocol = htons(ETH_P_IP); | ||
| 3060 | new_skb->dev = dev; | ||
| 3061 | new_skb->mac.raw = new_skb->data; | ||
| 3062 | |||
| 3063 | netif_rx(new_skb); | ||
| 3064 | dev->last_rx = jiffies; | ||
| 3065 | } else { | ||
| 3066 | |||
| 3067 | printk(KERN_INFO "%s: no socket buffers available!\n", | ||
| 3068 | card->devname); | ||
| 3069 | } | ||
| 3070 | } | ||
| 3071 | |||
| 3072 | chdlc_priv_area->udp_pkt_lgth = 0; | ||
| 3073 | |||
| 3074 | return 0; | ||
| 3075 | } | ||
| 3076 | |||
| 3077 | /*============================================================================ | ||
| 3078 | * Initialize Receive and Transmit Buffers. | ||
| 3079 | */ | ||
| 3080 | |||
| 3081 | static void init_chdlc_tx_rx_buff( sdla_t* card) | ||
| 3082 | { | ||
| 3083 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
| 3084 | CHDLC_TX_STATUS_EL_CFG_STRUCT *tx_config; | ||
| 3085 | CHDLC_RX_STATUS_EL_CFG_STRUCT *rx_config; | ||
| 3086 | char err; | ||
| 3087 | |||
| 3088 | mb->buffer_length = 0; | ||
| 3089 | mb->command = READ_CHDLC_CONFIGURATION; | ||
| 3090 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 3091 | |||
| 3092 | if(err != COMMAND_OK) { | ||
| 3093 | if (card->wandev.dev){ | ||
| 3094 | chdlc_error(card,err,mb); | ||
| 3095 | } | ||
| 3096 | return; | ||
| 3097 | } | ||
| 3098 | |||
| 3099 | if(card->hw.type == SDLA_S514) { | ||
| 3100 | tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + | ||
| 3101 | (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> | ||
| 3102 | ptr_CHDLC_Tx_stat_el_cfg_struct)); | ||
| 3103 | rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + | ||
| 3104 | (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> | ||
| 3105 | ptr_CHDLC_Rx_stat_el_cfg_struct)); | ||
| 3106 | |||
| 3107 | /* Setup Head and Tails for buffers */ | ||
| 3108 | card->u.c.txbuf_base = (void *)(card->hw.dpmbase + | ||
| 3109 | tx_config->base_addr_Tx_status_elements); | ||
| 3110 | card->u.c.txbuf_last = | ||
| 3111 | (CHDLC_DATA_TX_STATUS_EL_STRUCT *) | ||
| 3112 | card->u.c.txbuf_base + | ||
| 3113 | (tx_config->number_Tx_status_elements - 1); | ||
| 3114 | |||
| 3115 | card->u.c.rxbuf_base = (void *)(card->hw.dpmbase + | ||
| 3116 | rx_config->base_addr_Rx_status_elements); | ||
| 3117 | card->u.c.rxbuf_last = | ||
| 3118 | (CHDLC_DATA_RX_STATUS_EL_STRUCT *) | ||
| 3119 | card->u.c.rxbuf_base + | ||
| 3120 | (rx_config->number_Rx_status_elements - 1); | ||
| 3121 | |||
| 3122 | /* Set up next pointer to be used */ | ||
| 3123 | card->u.c.txbuf = (void *)(card->hw.dpmbase + | ||
| 3124 | tx_config->next_Tx_status_element_to_use); | ||
| 3125 | card->u.c.rxmb = (void *)(card->hw.dpmbase + | ||
| 3126 | rx_config->next_Rx_status_element_to_use); | ||
| 3127 | } | ||
| 3128 | else { | ||
| 3129 | tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + | ||
| 3130 | (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> | ||
| 3131 | ptr_CHDLC_Tx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); | ||
| 3132 | |||
| 3133 | rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + | ||
| 3134 | (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> | ||
| 3135 | ptr_CHDLC_Rx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); | ||
| 3136 | |||
| 3137 | /* Setup Head and Tails for buffers */ | ||
| 3138 | card->u.c.txbuf_base = (void *)(card->hw.dpmbase + | ||
| 3139 | (tx_config->base_addr_Tx_status_elements % SDLA_WINDOWSIZE)); | ||
| 3140 | card->u.c.txbuf_last = | ||
| 3141 | (CHDLC_DATA_TX_STATUS_EL_STRUCT *)card->u.c.txbuf_base | ||
| 3142 | + (tx_config->number_Tx_status_elements - 1); | ||
| 3143 | card->u.c.rxbuf_base = (void *)(card->hw.dpmbase + | ||
| 3144 | (rx_config->base_addr_Rx_status_elements % SDLA_WINDOWSIZE)); | ||
| 3145 | card->u.c.rxbuf_last = | ||
| 3146 | (CHDLC_DATA_RX_STATUS_EL_STRUCT *)card->u.c.rxbuf_base | ||
| 3147 | + (rx_config->number_Rx_status_elements - 1); | ||
| 3148 | |||
| 3149 | /* Set up next pointer to be used */ | ||
| 3150 | card->u.c.txbuf = (void *)(card->hw.dpmbase + | ||
| 3151 | (tx_config->next_Tx_status_element_to_use % SDLA_WINDOWSIZE)); | ||
| 3152 | card->u.c.rxmb = (void *)(card->hw.dpmbase + | ||
| 3153 | (rx_config->next_Rx_status_element_to_use % SDLA_WINDOWSIZE)); | ||
| 3154 | } | ||
| 3155 | |||
| 3156 | /* Setup Actual Buffer Start and end addresses */ | ||
| 3157 | card->u.c.rx_base = rx_config->base_addr_Rx_buffer; | ||
| 3158 | card->u.c.rx_top = rx_config->end_addr_Rx_buffer; | ||
| 3159 | |||
| 3160 | } | ||
| 3161 | |||
| 3162 | /*============================================================================= | ||
| 3163 | * Perform Interrupt Test by running READ_CHDLC_CODE_VERSION command MAX_INTR | ||
| 3164 | * _TEST_COUNTER times. | ||
| 3165 | */ | ||
| 3166 | static int intr_test( sdla_t* card) | ||
| 3167 | { | ||
| 3168 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
| 3169 | int err,i; | ||
| 3170 | |||
| 3171 | Intr_test_counter = 0; | ||
| 3172 | |||
| 3173 | err = chdlc_set_intr_mode(card, APP_INT_ON_COMMAND_COMPLETE); | ||
| 3174 | |||
| 3175 | if (err == CMD_OK) { | ||
| 3176 | for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) { | ||
| 3177 | mb->buffer_length = 0; | ||
| 3178 | mb->command = READ_CHDLC_CODE_VERSION; | ||
| 3179 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 3180 | if (err != CMD_OK) | ||
| 3181 | chdlc_error(card, err, mb); | ||
| 3182 | } | ||
| 3183 | } | ||
| 3184 | else { | ||
| 3185 | return err; | ||
| 3186 | } | ||
| 3187 | |||
| 3188 | err = chdlc_set_intr_mode(card, 0); | ||
| 3189 | |||
| 3190 | if (err != CMD_OK) | ||
| 3191 | return err; | ||
| 3192 | |||
| 3193 | return 0; | ||
| 3194 | } | ||
| 3195 | |||
| 3196 | /*============================================================================== | ||
| 3197 | * Determine what type of UDP call it is. CPIPEAB ? | ||
| 3198 | */ | ||
| 3199 | static int udp_pkt_type(struct sk_buff *skb, sdla_t* card) | ||
| 3200 | { | ||
| 3201 | chdlc_udp_pkt_t *chdlc_udp_pkt = (chdlc_udp_pkt_t *)skb->data; | ||
| 3202 | |||
| 3203 | #ifdef _WAN_UDP_DEBUG | ||
| 3204 | printk(KERN_INFO "SIG %s = %s\n\ | ||
| 3205 | UPP %x = %x\n\ | ||
| 3206 | PRT %x = %x\n\ | ||
| 3207 | REQ %i = %i\n\ | ||
| 3208 | 36 th = %x 37th = %x\n", | ||
| 3209 | chdlc_udp_pkt->wp_mgmt.signature, | ||
| 3210 | UDPMGMT_SIGNATURE, | ||
| 3211 | chdlc_udp_pkt->udp_pkt.udp_dst_port, | ||
| 3212 | ntohs(card->wandev.udp_port), | ||
| 3213 | chdlc_udp_pkt->ip_pkt.protocol, | ||
| 3214 | UDPMGMT_UDP_PROTOCOL, | ||
| 3215 | chdlc_udp_pkt->wp_mgmt.request_reply, | ||
| 3216 | UDPMGMT_REQUEST, | ||
| 3217 | skb->data[36], skb->data[37]); | ||
| 3218 | #endif | ||
| 3219 | |||
| 3220 | if (!strncmp(chdlc_udp_pkt->wp_mgmt.signature,UDPMGMT_SIGNATURE,8) && | ||
| 3221 | (chdlc_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) && | ||
| 3222 | (chdlc_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && | ||
| 3223 | (chdlc_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) { | ||
| 3224 | |||
| 3225 | return UDP_CPIPE_TYPE; | ||
| 3226 | |||
| 3227 | }else{ | ||
| 3228 | return UDP_INVALID_TYPE; | ||
| 3229 | } | ||
| 3230 | } | ||
| 3231 | |||
| 3232 | /*============================================================================ | ||
| 3233 | * Set PORT state. | ||
| 3234 | */ | ||
| 3235 | static void port_set_state (sdla_t *card, int state) | ||
| 3236 | { | ||
| 3237 | if (card->u.c.state != state) | ||
| 3238 | { | ||
| 3239 | switch (state) | ||
| 3240 | { | ||
| 3241 | case WAN_CONNECTED: | ||
| 3242 | printk (KERN_INFO "%s: Link connected!\n", | ||
| 3243 | card->devname); | ||
| 3244 | break; | ||
| 3245 | |||
| 3246 | case WAN_CONNECTING: | ||
| 3247 | printk (KERN_INFO "%s: Link connecting...\n", | ||
| 3248 | card->devname); | ||
| 3249 | break; | ||
| 3250 | |||
| 3251 | case WAN_DISCONNECTED: | ||
| 3252 | printk (KERN_INFO "%s: Link disconnected!\n", | ||
| 3253 | card->devname); | ||
| 3254 | break; | ||
| 3255 | } | ||
| 3256 | |||
| 3257 | card->wandev.state = card->u.c.state = state; | ||
| 3258 | if (card->wandev.dev){ | ||
| 3259 | struct net_device *dev = card->wandev.dev; | ||
| 3260 | chdlc_private_area_t *chdlc_priv_area = dev->priv; | ||
| 3261 | chdlc_priv_area->common.state = state; | ||
| 3262 | } | ||
| 3263 | } | ||
| 3264 | } | ||
| 3265 | |||
| 3266 | /*=========================================================================== | ||
| 3267 | * config_chdlc | ||
| 3268 | * | ||
| 3269 | * Configure the chdlc protocol and enable communications. | ||
| 3270 | * | ||
| 3271 | * The if_open() function binds this function to the poll routine. | ||
| 3272 | * Therefore, this function will run every time the chdlc interface | ||
| 3273 | * is brought up. We cannot run this function from the if_open | ||
| 3274 | * because if_open does not have access to the remote IP address. | ||
| 3275 | * | ||
| 3276 | * If the communications are not enabled, proceed to configure | ||
| 3277 | * the card and enable communications. | ||
| 3278 | * | ||
| 3279 | * If the communications are enabled, it means that the interface | ||
| 3280 | * was shutdown by ether the user or driver. In this case, we | ||
| 3281 | * have to check that the IP addresses have not changed. If | ||
| 3282 | * the IP addresses have changed, we have to reconfigure the firmware | ||
| 3283 | * and update the changed IP addresses. Otherwise, just exit. | ||
| 3284 | * | ||
| 3285 | */ | ||
| 3286 | |||
| 3287 | static int config_chdlc (sdla_t *card) | ||
| 3288 | { | ||
| 3289 | struct net_device *dev = card->wandev.dev; | ||
| 3290 | chdlc_private_area_t *chdlc_priv_area = dev->priv; | ||
| 3291 | SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; | ||
| 3292 | |||
| 3293 | if (card->u.c.comm_enabled){ | ||
| 3294 | |||
| 3295 | /* Jun 20. 2000: NC | ||
| 3296 | * IP addresses are not used in the API mode */ | ||
| 3297 | |||
| 3298 | if ((chdlc_priv_area->ip_local_tmp != chdlc_priv_area->ip_local || | ||
| 3299 | chdlc_priv_area->ip_remote_tmp != chdlc_priv_area->ip_remote) && | ||
| 3300 | card->u.c.usedby == WANPIPE) { | ||
| 3301 | |||
| 3302 | /* The IP addersses have changed, we must | ||
| 3303 | * stop the communications and reconfigure | ||
| 3304 | * the card. Reason: the firmware must know | ||
| 3305 | * the local and remote IP addresses. */ | ||
| 3306 | disable_comm(card); | ||
| 3307 | port_set_state(card, WAN_DISCONNECTED); | ||
| 3308 | printk(KERN_INFO | ||
| 3309 | "%s: IP addresses changed!\n", | ||
| 3310 | card->devname); | ||
| 3311 | printk(KERN_INFO | ||
| 3312 | "%s: Restarting communications ...\n", | ||
| 3313 | card->devname); | ||
| 3314 | }else{ | ||
| 3315 | /* IP addresses are the same and the link is up, | ||
| 3316 | * we don't have to do anything here. Therefore, exit */ | ||
| 3317 | return 0; | ||
| 3318 | } | ||
| 3319 | } | ||
| 3320 | |||
| 3321 | chdlc_priv_area->ip_local = chdlc_priv_area->ip_local_tmp; | ||
| 3322 | chdlc_priv_area->ip_remote = chdlc_priv_area->ip_remote_tmp; | ||
| 3323 | |||
| 3324 | |||
| 3325 | /* Setup the Board for asynchronous mode */ | ||
| 3326 | if (card->u.c.async_mode){ | ||
| 3327 | |||
| 3328 | if (set_asy_config(card)) { | ||
| 3329 | printk (KERN_INFO "%s: Failed CHDLC Async configuration!\n", | ||
| 3330 | card->devname); | ||
| 3331 | return 0; | ||
| 3332 | } | ||
| 3333 | }else{ | ||
| 3334 | /* Setup the Board for CHDLC */ | ||
| 3335 | if (set_chdlc_config(card)) { | ||
| 3336 | printk (KERN_INFO "%s: Failed CHDLC configuration!\n", | ||
| 3337 | card->devname); | ||
| 3338 | return 0; | ||
| 3339 | } | ||
| 3340 | } | ||
| 3341 | |||
| 3342 | /* Set interrupt mode and mask */ | ||
| 3343 | if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | | ||
| 3344 | APP_INT_ON_GLOBAL_EXCEP_COND | | ||
| 3345 | APP_INT_ON_TX_FRAME | | ||
| 3346 | APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){ | ||
| 3347 | printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", | ||
| 3348 | card->devname); | ||
| 3349 | return 0; | ||
| 3350 | } | ||
| 3351 | |||
| 3352 | |||
| 3353 | /* Mask the Transmit and Timer interrupt */ | ||
| 3354 | flags->interrupt_info_struct.interrupt_permission &= | ||
| 3355 | ~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER); | ||
| 3356 | |||
| 3357 | /* In TTY mode, receive interrupt will be enabled during | ||
| 3358 | * wanpipe_tty_open() operation */ | ||
| 3359 | if (card->tty_opt){ | ||
| 3360 | flags->interrupt_info_struct.interrupt_permission &= ~APP_INT_ON_RX_FRAME; | ||
| 3361 | } | ||
| 3362 | |||
| 3363 | /* Enable communications */ | ||
| 3364 | if (card->u.c.async_mode){ | ||
| 3365 | if (asy_comm_enable(card) != 0) { | ||
| 3366 | printk(KERN_INFO "%s: Failed to enable async commnunication!\n", | ||
| 3367 | card->devname); | ||
| 3368 | flags->interrupt_info_struct.interrupt_permission = 0; | ||
| 3369 | card->u.c.comm_enabled=0; | ||
| 3370 | chdlc_set_intr_mode(card,0); | ||
| 3371 | return 0; | ||
| 3372 | } | ||
| 3373 | }else{ | ||
| 3374 | if (chdlc_comm_enable(card) != 0) { | ||
| 3375 | printk(KERN_INFO "%s: Failed to enable chdlc communications!\n", | ||
| 3376 | card->devname); | ||
| 3377 | flags->interrupt_info_struct.interrupt_permission = 0; | ||
| 3378 | card->u.c.comm_enabled=0; | ||
| 3379 | chdlc_set_intr_mode(card,0); | ||
| 3380 | return 0; | ||
| 3381 | } | ||
| 3382 | } | ||
| 3383 | |||
| 3384 | /* Initialize Rx/Tx buffer control fields */ | ||
| 3385 | init_chdlc_tx_rx_buff(card); | ||
| 3386 | port_set_state(card, WAN_CONNECTING); | ||
| 3387 | return 0; | ||
| 3388 | } | ||
| 3389 | |||
| 3390 | |||
| 3391 | /*============================================================ | ||
| 3392 | * chdlc_poll | ||
| 3393 | * | ||
| 3394 | * Rationale: | ||
| 3395 | * We cannot manipulate the routing tables, or | ||
| 3396 | * ip addresses withing the interrupt. Therefore | ||
| 3397 | * we must perform such actons outside an interrupt | ||
| 3398 | * at a later time. | ||
| 3399 | * | ||
| 3400 | * Description: | ||
| 3401 | * CHDLC polling routine, responsible for | ||
| 3402 | * shutting down interfaces upon disconnect | ||
| 3403 | * and adding/removing routes. | ||
| 3404 | * | ||
| 3405 | * Usage: | ||
| 3406 | * This function is executed for each CHDLC | ||
| 3407 | * interface through a tq_schedule bottom half. | ||
| 3408 | * | ||
| 3409 | * trigger_chdlc_poll() function is used to kick | ||
| 3410 | * the chldc_poll routine. | ||
| 3411 | */ | ||
| 3412 | |||
| 3413 | static void chdlc_poll(struct net_device *dev) | ||
| 3414 | { | ||
| 3415 | chdlc_private_area_t *chdlc_priv_area; | ||
| 3416 | sdla_t *card; | ||
| 3417 | u8 check_gateway=0; | ||
| 3418 | SHARED_MEMORY_INFO_STRUCT* flags; | ||
| 3419 | |||
| 3420 | |||
| 3421 | if (!dev || (chdlc_priv_area=dev->priv) == NULL) | ||
| 3422 | return; | ||
| 3423 | |||
| 3424 | card = chdlc_priv_area->card; | ||
| 3425 | flags = card->u.c.flags; | ||
| 3426 | |||
| 3427 | /* (Re)Configuraiton is in progress, stop what you are | ||
| 3428 | * doing and get out */ | ||
| 3429 | if (test_bit(PERI_CRIT,&card->wandev.critical)){ | ||
| 3430 | clear_bit(POLL_CRIT,&card->wandev.critical); | ||
| 3431 | return; | ||
| 3432 | } | ||
| 3433 | |||
| 3434 | /* if_open() function has triggered the polling routine | ||
| 3435 | * to determine the configured IP addresses. Once the | ||
| 3436 | * addresses are found, trigger the chdlc configuration */ | ||
| 3437 | if (test_bit(0,&chdlc_priv_area->config_chdlc)){ | ||
| 3438 | |||
| 3439 | chdlc_priv_area->ip_local_tmp = get_ip_address(dev,WAN_LOCAL_IP); | ||
| 3440 | chdlc_priv_area->ip_remote_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP); | ||
| 3441 | |||
| 3442 | /* Jun 20. 2000 Bug Fix | ||
| 3443 | * Only perform this check in WANPIPE mode, since | ||
| 3444 | * IP addresses are not used in the API mode. */ | ||
| 3445 | |||
| 3446 | if (chdlc_priv_area->ip_local_tmp == chdlc_priv_area->ip_remote_tmp && | ||
| 3447 | card->u.c.slarp_timer == 0x00 && | ||
| 3448 | !card->u.c.backup && | ||
| 3449 | card->u.c.usedby == WANPIPE){ | ||
| 3450 | |||
| 3451 | if (++chdlc_priv_area->ip_error > MAX_IP_ERRORS){ | ||
| 3452 | printk(KERN_INFO "\n%s: --- WARNING ---\n", | ||
| 3453 | card->devname); | ||
| 3454 | printk(KERN_INFO | ||
| 3455 | "%s: The local IP address is the same as the\n", | ||
| 3456 | card->devname); | ||
| 3457 | printk(KERN_INFO | ||
| 3458 | "%s: Point-to-Point IP address.\n", | ||
| 3459 | card->devname); | ||
| 3460 | printk(KERN_INFO "%s: --- WARNING ---\n\n", | ||
| 3461 | card->devname); | ||
| 3462 | }else{ | ||
| 3463 | clear_bit(POLL_CRIT,&card->wandev.critical); | ||
| 3464 | chdlc_priv_area->poll_delay_timer.expires = jiffies+HZ; | ||
| 3465 | add_timer(&chdlc_priv_area->poll_delay_timer); | ||
| 3466 | return; | ||
| 3467 | } | ||
| 3468 | } | ||
| 3469 | |||
| 3470 | clear_bit(0,&chdlc_priv_area->config_chdlc); | ||
| 3471 | clear_bit(POLL_CRIT,&card->wandev.critical); | ||
| 3472 | |||
| 3473 | chdlc_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG; | ||
| 3474 | flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; | ||
| 3475 | return; | ||
| 3476 | } | ||
| 3477 | /* Dynamic interface implementation, as well as dynamic | ||
| 3478 | * routing. */ | ||
| 3479 | |||
| 3480 | switch (card->u.c.state){ | ||
| 3481 | |||
| 3482 | case WAN_DISCONNECTED: | ||
| 3483 | |||
| 3484 | /* If the dynamic interface configuration is on, and interface | ||
| 3485 | * is up, then bring down the netowrk interface */ | ||
| 3486 | |||
| 3487 | if (test_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down) && | ||
| 3488 | !test_bit(DEV_DOWN, &chdlc_priv_area->interface_down) && | ||
| 3489 | card->wandev.dev->flags & IFF_UP){ | ||
| 3490 | |||
| 3491 | printk(KERN_INFO "%s: Interface %s down.\n", | ||
| 3492 | card->devname,card->wandev.dev->name); | ||
| 3493 | change_dev_flags(card->wandev.dev,(card->wandev.dev->flags&~IFF_UP)); | ||
| 3494 | set_bit(DEV_DOWN,&chdlc_priv_area->interface_down); | ||
| 3495 | chdlc_priv_area->route_status = NO_ROUTE; | ||
| 3496 | |||
| 3497 | }else{ | ||
| 3498 | /* We need to check if the local IP address is | ||
| 3499 | * zero. If it is, we shouldn't try to remove it. | ||
| 3500 | */ | ||
| 3501 | |||
| 3502 | if (card->wandev.dev->flags & IFF_UP && | ||
| 3503 | get_ip_address(card->wandev.dev,WAN_LOCAL_IP) && | ||
| 3504 | chdlc_priv_area->route_status != NO_ROUTE && | ||
| 3505 | card->u.c.slarp_timer){ | ||
| 3506 | |||
| 3507 | process_route(card); | ||
| 3508 | } | ||
| 3509 | } | ||
| 3510 | break; | ||
| 3511 | |||
| 3512 | case WAN_CONNECTED: | ||
| 3513 | |||
| 3514 | /* In SMP machine this code can execute before the interface | ||
| 3515 | * comes up. In this case, we must make sure that we do not | ||
| 3516 | * try to bring up the interface before dev_open() is finished */ | ||
| 3517 | |||
| 3518 | |||
| 3519 | /* DEV_DOWN will be set only when we bring down the interface | ||
| 3520 | * for the very first time. This way we know that it was us | ||
| 3521 | * that brought the interface down */ | ||
| 3522 | |||
| 3523 | if (test_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down) && | ||
| 3524 | test_bit(DEV_DOWN, &chdlc_priv_area->interface_down) && | ||
| 3525 | !(card->wandev.dev->flags & IFF_UP)){ | ||
| 3526 | |||
| 3527 | printk(KERN_INFO "%s: Interface %s up.\n", | ||
| 3528 | card->devname,card->wandev.dev->name); | ||
| 3529 | change_dev_flags(card->wandev.dev,(card->wandev.dev->flags|IFF_UP)); | ||
| 3530 | clear_bit(DEV_DOWN,&chdlc_priv_area->interface_down); | ||
| 3531 | check_gateway=1; | ||
| 3532 | } | ||
| 3533 | |||
| 3534 | if (chdlc_priv_area->route_status == ADD_ROUTE && | ||
| 3535 | card->u.c.slarp_timer){ | ||
| 3536 | |||
| 3537 | process_route(card); | ||
| 3538 | check_gateway=1; | ||
| 3539 | } | ||
| 3540 | |||
| 3541 | if (chdlc_priv_area->gateway && check_gateway) | ||
| 3542 | add_gateway(card,dev); | ||
| 3543 | |||
| 3544 | break; | ||
| 3545 | } | ||
| 3546 | |||
| 3547 | clear_bit(POLL_CRIT,&card->wandev.critical); | ||
| 3548 | } | ||
| 3549 | |||
| 3550 | /*============================================================ | ||
| 3551 | * trigger_chdlc_poll | ||
| 3552 | * | ||
| 3553 | * Description: | ||
| 3554 | * Add a chdlc_poll() work entry into the keventd work queue | ||
| 3555 | * for a specific dlci/interface. This will kick | ||
| 3556 | * the fr_poll() routine at a later time. | ||
| 3557 | * | ||
| 3558 | * Usage: | ||
| 3559 | * Interrupts use this to defer a taks to | ||
| 3560 | * a polling routine. | ||
| 3561 | * | ||
| 3562 | */ | ||
| 3563 | static void trigger_chdlc_poll(struct net_device *dev) | ||
| 3564 | { | ||
| 3565 | chdlc_private_area_t *chdlc_priv_area; | ||
| 3566 | sdla_t *card; | ||
| 3567 | |||
| 3568 | if (!dev) | ||
| 3569 | return; | ||
| 3570 | |||
| 3571 | if ((chdlc_priv_area = dev->priv)==NULL) | ||
| 3572 | return; | ||
| 3573 | |||
| 3574 | card = chdlc_priv_area->card; | ||
| 3575 | |||
| 3576 | if (test_and_set_bit(POLL_CRIT,&card->wandev.critical)){ | ||
| 3577 | return; | ||
| 3578 | } | ||
| 3579 | if (test_bit(PERI_CRIT,&card->wandev.critical)){ | ||
| 3580 | return; | ||
| 3581 | } | ||
| 3582 | schedule_work(&chdlc_priv_area->poll_work); | ||
| 3583 | } | ||
| 3584 | |||
| 3585 | |||
| 3586 | static void chdlc_poll_delay (unsigned long dev_ptr) | ||
| 3587 | { | ||
| 3588 | struct net_device *dev = (struct net_device *)dev_ptr; | ||
| 3589 | trigger_chdlc_poll(dev); | ||
| 3590 | } | ||
| 3591 | |||
| 3592 | |||
| 3593 | void s508_lock (sdla_t *card, unsigned long *smp_flags) | ||
| 3594 | { | ||
| 3595 | spin_lock_irqsave(&card->wandev.lock, *smp_flags); | ||
| 3596 | if (card->next){ | ||
| 3597 | spin_lock(&card->next->wandev.lock); | ||
| 3598 | } | ||
| 3599 | } | ||
| 3600 | |||
| 3601 | void s508_unlock (sdla_t *card, unsigned long *smp_flags) | ||
| 3602 | { | ||
| 3603 | if (card->next){ | ||
| 3604 | spin_unlock(&card->next->wandev.lock); | ||
| 3605 | } | ||
| 3606 | spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); | ||
| 3607 | } | ||
| 3608 | |||
| 3609 | //*********** TTY SECTION **************** | ||
| 3610 | |||
| 3611 | static void wanpipe_tty_trigger_tx_irq(sdla_t *card) | ||
| 3612 | { | ||
| 3613 | SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; | ||
| 3614 | INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct; | ||
| 3615 | chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME; | ||
| 3616 | } | ||
| 3617 | |||
| 3618 | static void wanpipe_tty_trigger_poll(sdla_t *card) | ||
| 3619 | { | ||
| 3620 | schedule_work(&card->tty_work); | ||
| 3621 | } | ||
| 3622 | |||
| 3623 | static void tty_poll_work (void* data) | ||
| 3624 | { | ||
| 3625 | sdla_t *card = (sdla_t*)data; | ||
| 3626 | struct tty_struct *tty; | ||
| 3627 | |||
| 3628 | if ((tty=card->tty)==NULL) | ||
| 3629 | return; | ||
| 3630 | |||
| 3631 | tty_wakeup(tty); | ||
| 3632 | #if defined(SERIAL_HAVE_POLL_WAIT) | ||
| 3633 | wake_up_interruptible(&tty->poll_wait); | ||
| 3634 | #endif | ||
| 3635 | return; | ||
| 3636 | } | ||
| 3637 | |||
| 3638 | static void wanpipe_tty_close(struct tty_struct *tty, struct file * filp) | ||
| 3639 | { | ||
| 3640 | sdla_t *card; | ||
| 3641 | unsigned long smp_flags; | ||
| 3642 | |||
| 3643 | if (!tty || !tty->driver_data){ | ||
| 3644 | return; | ||
| 3645 | } | ||
| 3646 | |||
| 3647 | card = (sdla_t*)tty->driver_data; | ||
| 3648 | |||
| 3649 | if (!card) | ||
| 3650 | return; | ||
| 3651 | |||
| 3652 | printk(KERN_INFO "%s: Closing TTY Driver!\n", | ||
| 3653 | card->devname); | ||
| 3654 | |||
| 3655 | /* Sanity Check */ | ||
| 3656 | if (!card->tty_open) | ||
| 3657 | return; | ||
| 3658 | |||
| 3659 | wanpipe_close(card); | ||
| 3660 | if (--card->tty_open == 0){ | ||
| 3661 | |||
| 3662 | lock_adapter_irq(&card->wandev.lock,&smp_flags); | ||
| 3663 | card->tty=NULL; | ||
| 3664 | chdlc_disable_comm_shutdown(card); | ||
| 3665 | unlock_adapter_irq(&card->wandev.lock,&smp_flags); | ||
| 3666 | |||
| 3667 | kfree(card->tty_buf); | ||
| 3668 | card->tty_buf = NULL; | ||
| 3669 | kfree(card->tty_rx); | ||
| 3670 | card->tty_rx = NULL; | ||
| 3671 | } | ||
| 3672 | return; | ||
| 3673 | } | ||
| 3674 | static int wanpipe_tty_open(struct tty_struct *tty, struct file * filp) | ||
| 3675 | { | ||
| 3676 | unsigned long smp_flags; | ||
| 3677 | sdla_t *card; | ||
| 3678 | |||
| 3679 | if (!tty){ | ||
| 3680 | return -ENODEV; | ||
| 3681 | } | ||
| 3682 | |||
| 3683 | if (!tty->driver_data){ | ||
| 3684 | int port; | ||
| 3685 | port = tty->index; | ||
| 3686 | if ((port < 0) || (port >= NR_PORTS)) | ||
| 3687 | return -ENODEV; | ||
| 3688 | |||
| 3689 | tty->driver_data = WAN_CARD(port); | ||
| 3690 | if (!tty->driver_data) | ||
| 3691 | return -ENODEV; | ||
| 3692 | } | ||
| 3693 | |||
| 3694 | card = (sdla_t*)tty->driver_data; | ||
| 3695 | |||
| 3696 | if (!card){ | ||
| 3697 | lock_adapter_irq(&card->wandev.lock,&smp_flags); | ||
| 3698 | card->tty=NULL; | ||
| 3699 | unlock_adapter_irq(&card->wandev.lock,&smp_flags); | ||
| 3700 | return -ENODEV; | ||
| 3701 | } | ||
| 3702 | |||
| 3703 | printk(KERN_INFO "%s: Opening TTY Driver!\n", | ||
| 3704 | card->devname); | ||
| 3705 | |||
| 3706 | if (card->tty_open == 0){ | ||
| 3707 | lock_adapter_irq(&card->wandev.lock,&smp_flags); | ||
| 3708 | card->tty=tty; | ||
| 3709 | unlock_adapter_irq(&card->wandev.lock,&smp_flags); | ||
| 3710 | |||
| 3711 | if (!card->tty_buf){ | ||
| 3712 | card->tty_buf = kmalloc(TTY_CHDLC_MAX_MTU, GFP_KERNEL); | ||
| 3713 | if (!card->tty_buf){ | ||
| 3714 | card->tty_buf=NULL; | ||
| 3715 | card->tty=NULL; | ||
| 3716 | return -ENOMEM; | ||
| 3717 | } | ||
| 3718 | } | ||
| 3719 | |||
| 3720 | if (!card->tty_rx){ | ||
| 3721 | card->tty_rx = kmalloc(TTY_CHDLC_MAX_MTU, GFP_KERNEL); | ||
| 3722 | if (!card->tty_rx){ | ||
| 3723 | /* Free the buffer above */ | ||
| 3724 | kfree(card->tty_buf); | ||
| 3725 | card->tty_buf=NULL; | ||
| 3726 | card->tty=NULL; | ||
| 3727 | return -ENOMEM; | ||
| 3728 | } | ||
| 3729 | } | ||
| 3730 | } | ||
| 3731 | |||
| 3732 | ++card->tty_open; | ||
| 3733 | wanpipe_open(card); | ||
| 3734 | return 0; | ||
| 3735 | } | ||
| 3736 | |||
| 3737 | static int wanpipe_tty_write(struct tty_struct * tty, const unsigned char *buf, int count) | ||
| 3738 | { | ||
| 3739 | unsigned long smp_flags=0; | ||
| 3740 | sdla_t *card=NULL; | ||
| 3741 | |||
| 3742 | if (!tty){ | ||
| 3743 | dbg_printk(KERN_INFO "NO TTY in Write\n"); | ||
| 3744 | return -ENODEV; | ||
| 3745 | } | ||
| 3746 | |||
| 3747 | card = (sdla_t *)tty->driver_data; | ||
| 3748 | |||
| 3749 | if (!card){ | ||
| 3750 | dbg_printk(KERN_INFO "No Card in TTY Write\n"); | ||
| 3751 | return -ENODEV; | ||
| 3752 | } | ||
| 3753 | |||
| 3754 | if (count > card->wandev.mtu){ | ||
| 3755 | dbg_printk(KERN_INFO "Frame too big in Write %i Max: %i\n", | ||
| 3756 | count,card->wandev.mtu); | ||
| 3757 | return -EINVAL; | ||
| 3758 | } | ||
| 3759 | |||
| 3760 | if (card->wandev.state != WAN_CONNECTED){ | ||
| 3761 | dbg_printk(KERN_INFO "Card not connected in TTY Write\n"); | ||
| 3762 | return -EINVAL; | ||
| 3763 | } | ||
| 3764 | |||
| 3765 | /* Lock the 508 Card: SMP is supported */ | ||
| 3766 | if(card->hw.type != SDLA_S514){ | ||
| 3767 | s508_lock(card,&smp_flags); | ||
| 3768 | } | ||
| 3769 | |||
| 3770 | if (test_and_set_bit(SEND_CRIT,(void*)&card->wandev.critical)){ | ||
| 3771 | printk(KERN_INFO "%s: Critical in TTY Write\n", | ||
| 3772 | card->devname); | ||
| 3773 | |||
| 3774 | /* Lock the 508 Card: SMP is supported */ | ||
| 3775 | if(card->hw.type != SDLA_S514) | ||
| 3776 | s508_unlock(card,&smp_flags); | ||
| 3777 | |||
| 3778 | return -EINVAL; | ||
| 3779 | } | ||
| 3780 | |||
| 3781 | if (chdlc_send(card,(void*)buf,count)){ | ||
| 3782 | dbg_printk(KERN_INFO "%s: Failed to send, retry later: kernel!\n", | ||
| 3783 | card->devname); | ||
| 3784 | clear_bit(SEND_CRIT,(void*)&card->wandev.critical); | ||
| 3785 | |||
| 3786 | wanpipe_tty_trigger_tx_irq(card); | ||
| 3787 | |||
| 3788 | if(card->hw.type != SDLA_S514) | ||
| 3789 | s508_unlock(card,&smp_flags); | ||
| 3790 | return 0; | ||
| 3791 | } | ||
| 3792 | dbg_printk(KERN_INFO "%s: Packet sent OK: %i\n",card->devname,count); | ||
| 3793 | clear_bit(SEND_CRIT,(void*)&card->wandev.critical); | ||
| 3794 | |||
| 3795 | if(card->hw.type != SDLA_S514) | ||
| 3796 | s508_unlock(card,&smp_flags); | ||
| 3797 | |||
| 3798 | return count; | ||
| 3799 | } | ||
| 3800 | |||
| 3801 | static void wanpipe_tty_receive(sdla_t *card, unsigned addr, unsigned int len) | ||
| 3802 | { | ||
| 3803 | unsigned offset=0; | ||
| 3804 | unsigned olen=len; | ||
| 3805 | char fp=0; | ||
| 3806 | struct tty_struct *tty; | ||
| 3807 | int i; | ||
| 3808 | struct tty_ldisc *ld; | ||
| 3809 | |||
| 3810 | if (!card->tty_open){ | ||
| 3811 | dbg_printk(KERN_INFO "%s: TTY not open during receive\n", | ||
| 3812 | card->devname); | ||
| 3813 | return; | ||
| 3814 | } | ||
| 3815 | |||
| 3816 | if ((tty=card->tty) == NULL){ | ||
| 3817 | dbg_printk(KERN_INFO "%s: No TTY on receive\n", | ||
| 3818 | card->devname); | ||
| 3819 | return; | ||
| 3820 | } | ||
| 3821 | |||
| 3822 | if (!tty->driver_data){ | ||
| 3823 | dbg_printk(KERN_INFO "%s: No Driver Data, or Flip on receive\n", | ||
| 3824 | card->devname); | ||
| 3825 | return; | ||
| 3826 | } | ||
| 3827 | |||
| 3828 | |||
| 3829 | if (card->u.c.async_mode){ | ||
| 3830 | if ((tty->flip.count+len) >= TTY_FLIPBUF_SIZE){ | ||
| 3831 | if (net_ratelimit()){ | ||
| 3832 | printk(KERN_INFO | ||
| 3833 | "%s: Received packet size too big: %i bytes, Max: %i!\n", | ||
| 3834 | card->devname,len,TTY_FLIPBUF_SIZE); | ||
| 3835 | } | ||
| 3836 | return; | ||
| 3837 | } | ||
| 3838 | |||
| 3839 | |||
| 3840 | if((addr + len) > card->u.c.rx_top + 1) { | ||
| 3841 | offset = card->u.c.rx_top - addr + 1; | ||
| 3842 | |||
| 3843 | sdla_peek(&card->hw, addr, tty->flip.char_buf_ptr, offset); | ||
| 3844 | |||
| 3845 | addr = card->u.c.rx_base; | ||
| 3846 | len -= offset; | ||
| 3847 | |||
| 3848 | tty->flip.char_buf_ptr+=offset; | ||
| 3849 | tty->flip.count+=offset; | ||
| 3850 | for (i=0;i<offset;i++){ | ||
| 3851 | *tty->flip.flag_buf_ptr = 0; | ||
| 3852 | tty->flip.flag_buf_ptr++; | ||
| 3853 | } | ||
| 3854 | } | ||
| 3855 | |||
| 3856 | sdla_peek(&card->hw, addr, tty->flip.char_buf_ptr, len); | ||
| 3857 | |||
| 3858 | tty->flip.char_buf_ptr+=len; | ||
| 3859 | card->tty->flip.count+=len; | ||
| 3860 | for (i=0;i<len;i++){ | ||
| 3861 | *tty->flip.flag_buf_ptr = 0; | ||
| 3862 | tty->flip.flag_buf_ptr++; | ||
| 3863 | } | ||
| 3864 | |||
| 3865 | tty->low_latency=1; | ||
| 3866 | tty_flip_buffer_push(tty); | ||
| 3867 | }else{ | ||
| 3868 | if (!card->tty_rx){ | ||
| 3869 | if (net_ratelimit()){ | ||
| 3870 | printk(KERN_INFO | ||
| 3871 | "%s: Receive sync buffer not available!\n", | ||
| 3872 | card->devname); | ||
| 3873 | } | ||
| 3874 | return; | ||
| 3875 | } | ||
| 3876 | |||
| 3877 | if (len > TTY_CHDLC_MAX_MTU){ | ||
| 3878 | if (net_ratelimit()){ | ||
| 3879 | printk(KERN_INFO | ||
| 3880 | "%s: Received packet size too big: %i bytes, Max: %i!\n", | ||
| 3881 | card->devname,len,TTY_FLIPBUF_SIZE); | ||
| 3882 | } | ||
| 3883 | return; | ||
| 3884 | } | ||
| 3885 | |||
| 3886 | |||
| 3887 | if((addr + len) > card->u.c.rx_top + 1) { | ||
| 3888 | offset = card->u.c.rx_top - addr + 1; | ||
| 3889 | |||
| 3890 | sdla_peek(&card->hw, addr, card->tty_rx, offset); | ||
| 3891 | |||
| 3892 | addr = card->u.c.rx_base; | ||
| 3893 | len -= offset; | ||
| 3894 | } | ||
| 3895 | sdla_peek(&card->hw, addr, card->tty_rx+offset, len); | ||
| 3896 | ld = tty_ldisc_ref(tty); | ||
| 3897 | if (ld) { | ||
| 3898 | if (ld->receive_buf) | ||
| 3899 | ld->receive_buf(tty,card->tty_rx,&fp,olen); | ||
| 3900 | tty_ldisc_deref(ld); | ||
| 3901 | }else{ | ||
| 3902 | if (net_ratelimit()){ | ||
| 3903 | printk(KERN_INFO | ||
| 3904 | "%s: NO TTY Sync line discipline!\n", | ||
| 3905 | card->devname); | ||
| 3906 | } | ||
| 3907 | } | ||
| 3908 | } | ||
| 3909 | |||
| 3910 | dbg_printk(KERN_INFO "%s: Received Data %i\n",card->devname,olen); | ||
| 3911 | return; | ||
| 3912 | } | ||
| 3913 | |||
| 3914 | #if 0 | ||
| 3915 | static int wanpipe_tty_ioctl(struct tty_struct *tty, struct file * file, | ||
| 3916 | unsigned int cmd, unsigned long arg) | ||
| 3917 | { | ||
| 3918 | return -ENOIOCTLCMD; | ||
| 3919 | } | ||
| 3920 | #endif | ||
| 3921 | |||
| 3922 | static void wanpipe_tty_stop(struct tty_struct *tty) | ||
| 3923 | { | ||
| 3924 | return; | ||
| 3925 | } | ||
| 3926 | |||
| 3927 | static void wanpipe_tty_start(struct tty_struct *tty) | ||
| 3928 | { | ||
| 3929 | return; | ||
| 3930 | } | ||
| 3931 | |||
| 3932 | static int config_tty (sdla_t *card) | ||
| 3933 | { | ||
| 3934 | SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; | ||
| 3935 | |||
| 3936 | /* Setup the Board for asynchronous mode */ | ||
| 3937 | if (card->u.c.async_mode){ | ||
| 3938 | |||
| 3939 | if (set_asy_config(card)) { | ||
| 3940 | printk (KERN_INFO "%s: Failed CHDLC Async configuration!\n", | ||
| 3941 | card->devname); | ||
| 3942 | return -EINVAL; | ||
| 3943 | } | ||
| 3944 | }else{ | ||
| 3945 | /* Setup the Board for CHDLC */ | ||
| 3946 | if (set_chdlc_config(card)) { | ||
| 3947 | printk (KERN_INFO "%s: Failed CHDLC configuration!\n", | ||
| 3948 | card->devname); | ||
| 3949 | return -EINVAL; | ||
| 3950 | } | ||
| 3951 | } | ||
| 3952 | |||
| 3953 | /* Set interrupt mode and mask */ | ||
| 3954 | if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | | ||
| 3955 | APP_INT_ON_GLOBAL_EXCEP_COND | | ||
| 3956 | APP_INT_ON_TX_FRAME | | ||
| 3957 | APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){ | ||
| 3958 | printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", | ||
| 3959 | card->devname); | ||
| 3960 | return -EINVAL; | ||
| 3961 | } | ||
| 3962 | |||
| 3963 | |||
| 3964 | /* Mask the Transmit and Timer interrupt */ | ||
| 3965 | flags->interrupt_info_struct.interrupt_permission &= | ||
| 3966 | ~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER); | ||
| 3967 | |||
| 3968 | |||
| 3969 | /* Enable communications */ | ||
| 3970 | if (card->u.c.async_mode){ | ||
| 3971 | if (asy_comm_enable(card) != 0) { | ||
| 3972 | printk(KERN_INFO "%s: Failed to enable async commnunication!\n", | ||
| 3973 | card->devname); | ||
| 3974 | flags->interrupt_info_struct.interrupt_permission = 0; | ||
| 3975 | card->u.c.comm_enabled=0; | ||
| 3976 | chdlc_set_intr_mode(card,0); | ||
| 3977 | return -EINVAL; | ||
| 3978 | } | ||
| 3979 | }else{ | ||
| 3980 | if (chdlc_comm_enable(card) != 0) { | ||
| 3981 | printk(KERN_INFO "%s: Failed to enable chdlc communications!\n", | ||
| 3982 | card->devname); | ||
| 3983 | flags->interrupt_info_struct.interrupt_permission = 0; | ||
| 3984 | card->u.c.comm_enabled=0; | ||
| 3985 | chdlc_set_intr_mode(card,0); | ||
| 3986 | return -EINVAL; | ||
| 3987 | } | ||
| 3988 | } | ||
| 3989 | |||
| 3990 | /* Initialize Rx/Tx buffer control fields */ | ||
| 3991 | init_chdlc_tx_rx_buff(card); | ||
| 3992 | port_set_state(card, WAN_CONNECTING); | ||
| 3993 | return 0; | ||
| 3994 | } | ||
| 3995 | |||
| 3996 | |||
| 3997 | static int change_speed(sdla_t *card, struct tty_struct *tty, | ||
| 3998 | struct termios *old_termios) | ||
| 3999 | { | ||
| 4000 | int baud, ret=0; | ||
| 4001 | unsigned cflag; | ||
| 4002 | int dbits,sbits,parity,handshaking; | ||
| 4003 | |||
| 4004 | cflag = tty->termios->c_cflag; | ||
| 4005 | |||
| 4006 | /* There is always one stop bit */ | ||
| 4007 | sbits=WANOPT_ONE; | ||
| 4008 | |||
| 4009 | /* Parity is defaulted to NONE */ | ||
| 4010 | parity = WANOPT_NONE; | ||
| 4011 | |||
| 4012 | handshaking=0; | ||
| 4013 | |||
| 4014 | /* byte size and parity */ | ||
| 4015 | switch (cflag & CSIZE) { | ||
| 4016 | case CS5: dbits = 5; break; | ||
| 4017 | case CS6: dbits = 6; break; | ||
| 4018 | case CS7: dbits = 7; break; | ||
| 4019 | case CS8: dbits = 8; break; | ||
| 4020 | /* Never happens, but GCC is too dumb to figure it out */ | ||
| 4021 | default: dbits = 8; break; | ||
| 4022 | } | ||
| 4023 | |||
| 4024 | /* One more stop bit should be supported, thus increment | ||
| 4025 | * the number of stop bits Max=2 */ | ||
| 4026 | if (cflag & CSTOPB) { | ||
| 4027 | sbits = WANOPT_TWO; | ||
| 4028 | } | ||
| 4029 | if (cflag & PARENB) { | ||
| 4030 | parity = WANOPT_EVEN; | ||
| 4031 | } | ||
| 4032 | if (cflag & PARODD){ | ||
| 4033 | parity = WANOPT_ODD; | ||
| 4034 | } | ||
| 4035 | |||
| 4036 | /* Determine divisor based on baud rate */ | ||
| 4037 | baud = tty_get_baud_rate(tty); | ||
| 4038 | |||
| 4039 | if (!baud) | ||
| 4040 | baud = 9600; /* B0 transition handled in rs_set_termios */ | ||
| 4041 | |||
| 4042 | if (cflag & CRTSCTS) { | ||
| 4043 | handshaking|=ASY_RTS_HS_FOR_RX; | ||
| 4044 | } | ||
| 4045 | |||
| 4046 | if (I_IGNPAR(tty)) | ||
| 4047 | parity = WANOPT_NONE; | ||
| 4048 | |||
| 4049 | if (I_IXOFF(tty)){ | ||
| 4050 | handshaking|=ASY_XON_XOFF_HS_FOR_RX; | ||
| 4051 | handshaking|=ASY_XON_XOFF_HS_FOR_TX; | ||
| 4052 | } | ||
| 4053 | |||
| 4054 | if (I_IXON(tty)){ | ||
| 4055 | handshaking|=ASY_XON_XOFF_HS_FOR_RX; | ||
| 4056 | handshaking|=ASY_XON_XOFF_HS_FOR_TX; | ||
| 4057 | } | ||
| 4058 | |||
| 4059 | if (card->u.c.async_mode){ | ||
| 4060 | if (card->wandev.bps != baud) | ||
| 4061 | ret=1; | ||
| 4062 | card->wandev.bps = baud; | ||
| 4063 | } | ||
| 4064 | |||
| 4065 | if (card->u.c.async_mode){ | ||
| 4066 | if (card->u.c.protocol_options != handshaking) | ||
| 4067 | ret=1; | ||
| 4068 | card->u.c.protocol_options = handshaking; | ||
| 4069 | |||
| 4070 | if (card->u.c.tx_bits_per_char != dbits) | ||
| 4071 | ret=1; | ||
| 4072 | card->u.c.tx_bits_per_char = dbits; | ||
| 4073 | |||
| 4074 | if (card->u.c.rx_bits_per_char != dbits) | ||
| 4075 | ret=1; | ||
| 4076 | card->u.c.rx_bits_per_char = dbits; | ||
| 4077 | |||
| 4078 | if (card->u.c.stop_bits != sbits) | ||
| 4079 | ret=1; | ||
| 4080 | card->u.c.stop_bits = sbits; | ||
| 4081 | |||
| 4082 | if (card->u.c.parity != parity) | ||
| 4083 | ret=1; | ||
| 4084 | card->u.c.parity = parity; | ||
| 4085 | |||
| 4086 | card->u.c.break_timer = 50; | ||
| 4087 | card->u.c.inter_char_timer = 10; | ||
| 4088 | card->u.c.rx_complete_length = 100; | ||
| 4089 | card->u.c.xon_char = 0xFE; | ||
| 4090 | }else{ | ||
| 4091 | card->u.c.protocol_options = HDLC_STREAMING_MODE; | ||
| 4092 | } | ||
| 4093 | |||
| 4094 | return ret; | ||
| 4095 | } | ||
| 4096 | |||
| 4097 | |||
| 4098 | static void wanpipe_tty_set_termios(struct tty_struct *tty, struct termios *old_termios) | ||
| 4099 | { | ||
| 4100 | sdla_t *card; | ||
| 4101 | int err=1; | ||
| 4102 | |||
| 4103 | if (!tty){ | ||
| 4104 | return; | ||
| 4105 | } | ||
| 4106 | |||
| 4107 | card = (sdla_t *)tty->driver_data; | ||
| 4108 | |||
| 4109 | if (!card) | ||
| 4110 | return; | ||
| 4111 | |||
| 4112 | if (change_speed(card, tty, old_termios) || !card->u.c.comm_enabled){ | ||
| 4113 | unsigned long smp_flags; | ||
| 4114 | |||
| 4115 | if (card->u.c.comm_enabled){ | ||
| 4116 | lock_adapter_irq(&card->wandev.lock,&smp_flags); | ||
| 4117 | chdlc_disable_comm_shutdown(card); | ||
| 4118 | unlock_adapter_irq(&card->wandev.lock,&smp_flags); | ||
| 4119 | } | ||
| 4120 | lock_adapter_irq(&card->wandev.lock,&smp_flags); | ||
| 4121 | err = config_tty(card); | ||
| 4122 | unlock_adapter_irq(&card->wandev.lock,&smp_flags); | ||
| 4123 | if (card->u.c.async_mode){ | ||
| 4124 | printk(KERN_INFO "%s: TTY Async Configuration:\n" | ||
| 4125 | " Baud =%i\n" | ||
| 4126 | " Handshaking =%s\n" | ||
| 4127 | " Tx Dbits =%i\n" | ||
| 4128 | " Rx Dbits =%i\n" | ||
| 4129 | " Parity =%s\n" | ||
| 4130 | " Stop Bits =%i\n", | ||
| 4131 | card->devname, | ||
| 4132 | card->wandev.bps, | ||
| 4133 | opt_decode[card->u.c.protocol_options], | ||
| 4134 | card->u.c.tx_bits_per_char, | ||
| 4135 | card->u.c.rx_bits_per_char, | ||
| 4136 | p_decode[card->u.c.parity] , | ||
| 4137 | card->u.c.stop_bits); | ||
| 4138 | }else{ | ||
| 4139 | printk(KERN_INFO "%s: TTY Sync Configuration:\n" | ||
| 4140 | " Baud =%i\n" | ||
| 4141 | " Protocol =HDLC_STREAMING\n", | ||
| 4142 | card->devname,card->wandev.bps); | ||
| 4143 | } | ||
| 4144 | if (!err){ | ||
| 4145 | port_set_state(card,WAN_CONNECTED); | ||
| 4146 | }else{ | ||
| 4147 | port_set_state(card,WAN_DISCONNECTED); | ||
| 4148 | } | ||
| 4149 | } | ||
| 4150 | return; | ||
| 4151 | } | ||
| 4152 | |||
| 4153 | static void wanpipe_tty_put_char(struct tty_struct *tty, unsigned char ch) | ||
| 4154 | { | ||
| 4155 | sdla_t *card; | ||
| 4156 | unsigned long smp_flags=0; | ||
| 4157 | |||
| 4158 | if (!tty){ | ||
| 4159 | return; | ||
| 4160 | } | ||
| 4161 | |||
| 4162 | card = (sdla_t *)tty->driver_data; | ||
| 4163 | |||
| 4164 | if (!card) | ||
| 4165 | return; | ||
| 4166 | |||
| 4167 | if (card->wandev.state != WAN_CONNECTED) | ||
| 4168 | return; | ||
| 4169 | |||
| 4170 | if(card->hw.type != SDLA_S514) | ||
| 4171 | s508_lock(card,&smp_flags); | ||
| 4172 | |||
| 4173 | if (test_and_set_bit(SEND_CRIT,(void*)&card->wandev.critical)){ | ||
| 4174 | |||
| 4175 | wanpipe_tty_trigger_tx_irq(card); | ||
| 4176 | |||
| 4177 | if(card->hw.type != SDLA_S514) | ||
| 4178 | s508_unlock(card,&smp_flags); | ||
| 4179 | return; | ||
| 4180 | } | ||
| 4181 | |||
| 4182 | if (chdlc_send(card,(void*)&ch,1)){ | ||
| 4183 | wanpipe_tty_trigger_tx_irq(card); | ||
| 4184 | dbg_printk("%s: Failed to TX char!\n",card->devname); | ||
| 4185 | } | ||
| 4186 | |||
| 4187 | dbg_printk("%s: Char TX OK\n",card->devname); | ||
| 4188 | |||
| 4189 | clear_bit(SEND_CRIT,(void*)&card->wandev.critical); | ||
| 4190 | |||
| 4191 | if(card->hw.type != SDLA_S514) | ||
| 4192 | s508_unlock(card,&smp_flags); | ||
| 4193 | |||
| 4194 | return; | ||
| 4195 | } | ||
| 4196 | |||
| 4197 | static void wanpipe_tty_flush_chars(struct tty_struct *tty) | ||
| 4198 | { | ||
| 4199 | return; | ||
| 4200 | } | ||
| 4201 | |||
| 4202 | static void wanpipe_tty_flush_buffer(struct tty_struct *tty) | ||
| 4203 | { | ||
| 4204 | if (!tty) | ||
| 4205 | return; | ||
| 4206 | |||
| 4207 | #if defined(SERIAL_HAVE_POLL_WAIT) | ||
| 4208 | wake_up_interruptible(&tty->poll_wait); | ||
| 4209 | #endif | ||
| 4210 | tty_wakeup(tty); | ||
| 4211 | return; | ||
| 4212 | } | ||
| 4213 | |||
| 4214 | /* | ||
| 4215 | * This function is used to send a high-priority XON/XOFF character to | ||
| 4216 | * the device | ||
| 4217 | */ | ||
| 4218 | static void wanpipe_tty_send_xchar(struct tty_struct *tty, char ch) | ||
| 4219 | { | ||
| 4220 | return; | ||
| 4221 | } | ||
| 4222 | |||
| 4223 | |||
| 4224 | static int wanpipe_tty_chars_in_buffer(struct tty_struct *tty) | ||
| 4225 | { | ||
| 4226 | return 0; | ||
| 4227 | } | ||
| 4228 | |||
| 4229 | |||
| 4230 | static int wanpipe_tty_write_room(struct tty_struct *tty) | ||
| 4231 | { | ||
| 4232 | sdla_t *card; | ||
| 4233 | |||
| 4234 | printk(KERN_INFO "TTY Write Room\n"); | ||
| 4235 | |||
| 4236 | if (!tty){ | ||
| 4237 | return 0; | ||
| 4238 | } | ||
| 4239 | |||
| 4240 | card = (sdla_t *)tty->driver_data; | ||
| 4241 | if (!card) | ||
| 4242 | return 0; | ||
| 4243 | |||
| 4244 | if (card->wandev.state != WAN_CONNECTED) | ||
| 4245 | return 0; | ||
| 4246 | |||
| 4247 | return SEC_MAX_NO_DATA_BYTES_IN_FRAME; | ||
| 4248 | } | ||
| 4249 | |||
| 4250 | |||
| 4251 | static int set_modem_status(sdla_t *card, unsigned char data) | ||
| 4252 | { | ||
| 4253 | CHDLC_MAILBOX_STRUCT *mb = card->mbox; | ||
| 4254 | int err; | ||
| 4255 | |||
| 4256 | mb->buffer_length=1; | ||
| 4257 | mb->command=SET_MODEM_STATUS; | ||
| 4258 | mb->data[0]=data; | ||
| 4259 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 4260 | if (err != COMMAND_OK) | ||
| 4261 | chdlc_error (card, err, mb); | ||
| 4262 | |||
| 4263 | return err; | ||
| 4264 | } | ||
| 4265 | |||
| 4266 | static void wanpipe_tty_hangup(struct tty_struct *tty) | ||
| 4267 | { | ||
| 4268 | sdla_t *card; | ||
| 4269 | unsigned long smp_flags; | ||
| 4270 | |||
| 4271 | printk(KERN_INFO "TTY Hangup!\n"); | ||
| 4272 | |||
| 4273 | if (!tty){ | ||
| 4274 | return; | ||
| 4275 | } | ||
| 4276 | |||
| 4277 | card = (sdla_t *)tty->driver_data; | ||
| 4278 | if (!card) | ||
| 4279 | return; | ||
| 4280 | |||
| 4281 | lock_adapter_irq(&card->wandev.lock,&smp_flags); | ||
| 4282 | set_modem_status(card,0); | ||
| 4283 | unlock_adapter_irq(&card->wandev.lock,&smp_flags); | ||
| 4284 | return; | ||
| 4285 | } | ||
| 4286 | |||
| 4287 | static void wanpipe_tty_break(struct tty_struct *tty, int break_state) | ||
| 4288 | { | ||
| 4289 | return; | ||
| 4290 | } | ||
| 4291 | |||
| 4292 | static void wanpipe_tty_wait_until_sent(struct tty_struct *tty, int timeout) | ||
| 4293 | { | ||
| 4294 | return; | ||
| 4295 | } | ||
| 4296 | |||
| 4297 | static void wanpipe_tty_throttle(struct tty_struct * tty) | ||
| 4298 | { | ||
| 4299 | return; | ||
| 4300 | } | ||
| 4301 | |||
| 4302 | static void wanpipe_tty_unthrottle(struct tty_struct * tty) | ||
| 4303 | { | ||
| 4304 | return; | ||
| 4305 | } | ||
| 4306 | |||
| 4307 | int wanpipe_tty_read_proc(char *page, char **start, off_t off, int count, | ||
| 4308 | int *eof, void *data) | ||
| 4309 | { | ||
| 4310 | return 0; | ||
| 4311 | } | ||
| 4312 | |||
| 4313 | /* | ||
| 4314 | * The serial driver boot-time initialization code! | ||
| 4315 | */ | ||
| 4316 | int wanpipe_tty_init(sdla_t *card) | ||
| 4317 | { | ||
| 4318 | struct serial_state * state; | ||
| 4319 | |||
| 4320 | /* Initialize the tty_driver structure */ | ||
| 4321 | |||
| 4322 | if (card->tty_minor < 0 || card->tty_minor > NR_PORTS){ | ||
| 4323 | printk(KERN_INFO "%s: Illegal Minor TTY number (0-4): %i\n", | ||
| 4324 | card->devname,card->tty_minor); | ||
| 4325 | return -EINVAL; | ||
| 4326 | } | ||
| 4327 | |||
| 4328 | if (WAN_CARD(card->tty_minor)){ | ||
| 4329 | printk(KERN_INFO "%s: TTY Minor %i, already in use\n", | ||
| 4330 | card->devname,card->tty_minor); | ||
| 4331 | return -EBUSY; | ||
| 4332 | } | ||
| 4333 | |||
| 4334 | if (tty_init_cnt==0){ | ||
| 4335 | |||
| 4336 | printk(KERN_INFO "%s: TTY %s Driver Init: Major %i, Minor Range %i-%i\n", | ||
| 4337 | card->devname, | ||
| 4338 | card->u.c.async_mode ? "ASYNC" : "SYNC", | ||
| 4339 | WAN_TTY_MAJOR,MIN_PORT,MAX_PORT); | ||
| 4340 | |||
| 4341 | tty_driver_mode = card->u.c.async_mode; | ||
| 4342 | |||
| 4343 | memset(&serial_driver, 0, sizeof(struct tty_driver)); | ||
| 4344 | serial_driver.magic = TTY_DRIVER_MAGIC; | ||
| 4345 | serial_driver.owner = THIS_MODULE; | ||
| 4346 | serial_driver.driver_name = "wanpipe_tty"; | ||
| 4347 | serial_driver.name = "ttyW"; | ||
| 4348 | serial_driver.major = WAN_TTY_MAJOR; | ||
| 4349 | serial_driver.minor_start = WAN_TTY_MINOR; | ||
| 4350 | serial_driver.num = NR_PORTS; | ||
| 4351 | serial_driver.type = TTY_DRIVER_TYPE_SERIAL; | ||
| 4352 | serial_driver.subtype = SERIAL_TYPE_NORMAL; | ||
| 4353 | |||
| 4354 | serial_driver.init_termios = tty_std_termios; | ||
| 4355 | serial_driver.init_termios.c_cflag = | ||
| 4356 | B9600 | CS8 | CREAD | HUPCL | CLOCAL; | ||
| 4357 | serial_driver.flags = TTY_DRIVER_REAL_RAW; | ||
| 4358 | |||
| 4359 | serial_driver.refcount = 1; /* !@!@^#^&!! */ | ||
| 4360 | |||
| 4361 | serial_driver.open = wanpipe_tty_open; | ||
| 4362 | serial_driver.close = wanpipe_tty_close; | ||
| 4363 | serial_driver.write = wanpipe_tty_write; | ||
| 4364 | |||
| 4365 | serial_driver.put_char = wanpipe_tty_put_char; | ||
| 4366 | serial_driver.flush_chars = wanpipe_tty_flush_chars; | ||
| 4367 | serial_driver.write_room = wanpipe_tty_write_room; | ||
| 4368 | serial_driver.chars_in_buffer = wanpipe_tty_chars_in_buffer; | ||
| 4369 | serial_driver.flush_buffer = wanpipe_tty_flush_buffer; | ||
| 4370 | //serial_driver.ioctl = wanpipe_tty_ioctl; | ||
| 4371 | serial_driver.throttle = wanpipe_tty_throttle; | ||
| 4372 | serial_driver.unthrottle = wanpipe_tty_unthrottle; | ||
| 4373 | serial_driver.send_xchar = wanpipe_tty_send_xchar; | ||
| 4374 | serial_driver.set_termios = wanpipe_tty_set_termios; | ||
| 4375 | serial_driver.stop = wanpipe_tty_stop; | ||
| 4376 | serial_driver.start = wanpipe_tty_start; | ||
| 4377 | serial_driver.hangup = wanpipe_tty_hangup; | ||
| 4378 | serial_driver.break_ctl = wanpipe_tty_break; | ||
| 4379 | serial_driver.wait_until_sent = wanpipe_tty_wait_until_sent; | ||
| 4380 | serial_driver.read_proc = wanpipe_tty_read_proc; | ||
| 4381 | |||
| 4382 | if (tty_register_driver(&serial_driver)){ | ||
| 4383 | printk(KERN_INFO "%s: Failed to register serial driver!\n", | ||
| 4384 | card->devname); | ||
| 4385 | } | ||
| 4386 | } | ||
| 4387 | |||
| 4388 | |||
| 4389 | /* The subsequent ports must comply to the initial configuration */ | ||
| 4390 | if (tty_driver_mode != card->u.c.async_mode){ | ||
| 4391 | printk(KERN_INFO "%s: Error: TTY Driver operation mode mismatch!\n", | ||
| 4392 | card->devname); | ||
| 4393 | printk(KERN_INFO "%s: The TTY driver is configured for %s!\n", | ||
| 4394 | card->devname, tty_driver_mode ? "ASYNC" : "SYNC"); | ||
| 4395 | return -EINVAL; | ||
| 4396 | } | ||
| 4397 | |||
| 4398 | tty_init_cnt++; | ||
| 4399 | |||
| 4400 | printk(KERN_INFO "%s: Initializing TTY %s Driver Minor %i\n", | ||
| 4401 | card->devname, | ||
| 4402 | tty_driver_mode ? "ASYNC" : "SYNC", | ||
| 4403 | card->tty_minor); | ||
| 4404 | |||
| 4405 | tty_card_map[card->tty_minor] = card; | ||
| 4406 | state = &rs_table[card->tty_minor]; | ||
| 4407 | |||
| 4408 | state->magic = SSTATE_MAGIC; | ||
| 4409 | state->line = 0; | ||
| 4410 | state->type = PORT_UNKNOWN; | ||
| 4411 | state->custom_divisor = 0; | ||
| 4412 | state->close_delay = 5*HZ/10; | ||
| 4413 | state->closing_wait = 30*HZ; | ||
| 4414 | state->icount.cts = state->icount.dsr = | ||
| 4415 | state->icount.rng = state->icount.dcd = 0; | ||
| 4416 | state->icount.rx = state->icount.tx = 0; | ||
| 4417 | state->icount.frame = state->icount.parity = 0; | ||
| 4418 | state->icount.overrun = state->icount.brk = 0; | ||
| 4419 | state->irq = card->wandev.irq; | ||
| 4420 | |||
| 4421 | INIT_WORK(&card->tty_work, tty_poll_work, (void*)card); | ||
| 4422 | return 0; | ||
| 4423 | } | ||
| 4424 | |||
| 4425 | |||
| 4426 | MODULE_LICENSE("GPL"); | ||
| 4427 | |||
| 4428 | /****** End ****************************************************************/ | ||
diff --git a/drivers/net/wan/sdla_fr.c b/drivers/net/wan/sdla_fr.c deleted file mode 100644 index 7f1ce9d4333e..000000000000 --- a/drivers/net/wan/sdla_fr.c +++ /dev/null | |||
| @@ -1,5061 +0,0 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * sdla_fr.c WANPIPE(tm) Multiprotocol WAN Link Driver. Frame relay module. | ||
| 3 | * | ||
| 4 | * Author(s): Nenad Corbic <ncorbic@sangoma.com> | ||
| 5 | * Gideon Hack | ||
| 6 | * | ||
| 7 | * Copyright: (c) 1995-2001 Sangoma Technologies Inc. | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or | ||
| 10 | * modify it under the terms of the GNU General Public License | ||
| 11 | * as published by the Free Software Foundation; either version | ||
| 12 | * 2 of the License, or (at your option) any later version. | ||
| 13 | * ============================================================================ | ||
| 14 | * Nov 23, 2000 Nenad Corbic o Added support for 2.4.X kernels | ||
| 15 | * Nov 15, 2000 David Rokavarg | ||
| 16 | * Nenad Corbic o Added frame relay bridging support. | ||
| 17 | * Original code from Mark Wells and Kristian Hoffmann has | ||
| 18 | * been integrated into the frame relay driver. | ||
| 19 | * Nov 13, 2000 Nenad Corbic o Added true interface type encoding option. | ||
| 20 | * Tcpdump doesn't support Frame Relay inteface | ||
| 21 | * types, to fix this true type option will set | ||
| 22 | * the interface type to RAW IP mode. | ||
| 23 | * Nov 07, 2000 Nenad Corbic o Added security features for UDP debugging: | ||
| 24 | * Deny all and specify allowed requests. | ||
| 25 | * Nov 06, 2000 Nenad Corbic o Wanpipe interfaces conform to raw packet interfaces. | ||
| 26 | * Moved the if_header into the if_send() routine. | ||
| 27 | * The if_header() was breaking the libpcap | ||
| 28 | * support. i.e. support for tcpdump, ethereal ... | ||
| 29 | * Oct 12. 2000 Nenad Corbic o Added error message in fr_configure | ||
| 30 | * Jul 31, 2000 Nenad Corbic o Fixed the Router UP Time. | ||
| 31 | * Apr 28, 2000 Nenad Corbic o Added the option to shutdown an interface | ||
| 32 | * when the channel gets disconnected. | ||
| 33 | * Apr 28, 2000 Nenad Corbic o Added M.Grants patch: disallow duplicate | ||
| 34 | * interface setups. | ||
| 35 | * Apr 25, 2000 Nenad Corbic o Added M.Grants patch: dynamically add/remove | ||
| 36 | * new dlcis/interfaces. | ||
| 37 | * Mar 23, 2000 Nenad Corbic o Improved task queue, bh handling. | ||
| 38 | * Mar 16, 2000 Nenad Corbic o Added Inverse ARP support | ||
| 39 | * Mar 13, 2000 Nenad Corbic o Added new socket API support. | ||
| 40 | * Mar 06, 2000 Nenad Corbic o Bug Fix: corrupted mbox recovery. | ||
| 41 | * Feb 24, 2000 Nenad Corbic o Fixed up FT1 UDP debugging problem. | ||
| 42 | * Dev 15, 1999 Nenad Corbic o Fixed up header files for 2.0.X kernels | ||
| 43 | * | ||
| 44 | * Nov 08, 1999 Nenad Corbic o Combined all debug UDP calls into one function | ||
| 45 | * o Removed the ARP support. This has to be done | ||
| 46 | * in the next version. | ||
| 47 | * o Only a Node can implement NO signalling. | ||
| 48 | * Initialize DLCI during if_open() if NO | ||
| 49 | * signalling. | ||
| 50 | * o Took out IPX support, implement in next | ||
| 51 | * version | ||
| 52 | * Sep 29, 1999 Nenad Corbic o Added SMP support and changed the update | ||
| 53 | * function to use timer interrupt. | ||
| 54 | * o Fixed the CIR bug: Set the value of BC | ||
| 55 | * to CIR when the CIR is enabled. | ||
| 56 | * o Updated comments, statistics and tracing. | ||
| 57 | * Jun 02, 1999 Gideon Hack o Updated for S514 support. | ||
| 58 | * Sep 18, 1998 Jaspreet Singh o Updated for 2.2.X kernels. | ||
| 59 | * Jul 31, 1998 Jaspreet Singh o Removed wpf_poll routine. The channel/DLCI | ||
| 60 | * status is received through an event interrupt. | ||
| 61 | * Jul 08, 1998 David Fong o Added inverse ARP support. | ||
| 62 | * Mar 26, 1997 Jaspreet Singh o Returning return codes for failed UDP cmds. | ||
| 63 | * Jan 28, 1997 Jaspreet Singh o Improved handling of inactive DLCIs. | ||
| 64 | * Dec 30, 1997 Jaspreet Singh o Replaced dev_tint() with mark_bh(NET_BH) | ||
| 65 | * Dec 16, 1997 Jaspreet Singh o Implemented Multiple IPX support. | ||
| 66 | * Nov 26, 1997 Jaspreet Singh o Improved load sharing with multiple boards | ||
| 67 | * o Added Cli() to protect enabling of interrupts | ||
| 68 | * while polling is called. | ||
| 69 | * Nov 24, 1997 Jaspreet Singh o Added counters to avoid enabling of interrupts | ||
| 70 | * when they have been disabled by another | ||
| 71 | * interface or routine (eg. wpf_poll). | ||
| 72 | * Nov 06, 1997 Jaspreet Singh o Added INTR_TEST_MODE to avoid polling | ||
| 73 | * routine disable interrupts during interrupt | ||
| 74 | * testing. | ||
| 75 | * Oct 20, 1997 Jaspreet Singh o Added hooks in for Router UP time. | ||
| 76 | * Oct 16, 1997 Jaspreet Singh o The critical flag is used to maintain flow | ||
| 77 | * control by avoiding RACE conditions. The | ||
| 78 | * cli() and restore_flags() are taken out. | ||
| 79 | * The fr_channel structure is appended for | ||
| 80 | * Driver Statistics. | ||
| 81 | * Oct 15, 1997 Farhan Thawar o updated if_send() and receive for IPX | ||
| 82 | * Aug 29, 1997 Farhan Thawar o Removed most of the cli() and sti() | ||
| 83 | * o Abstracted the UDP management stuff | ||
| 84 | * o Now use tbusy and critical more intelligently | ||
| 85 | * Jul 21, 1997 Jaspreet Singh o Can configure T391, T392, N391, N392 & N393 | ||
| 86 | * through router.conf. | ||
| 87 | * o Protected calls to sdla_peek() by adDing | ||
| 88 | * save_flags(), cli() and restore_flags(). | ||
| 89 | * o Added error message for Inactive DLCIs in | ||
| 90 | * fr_event() and update_chan_state(). | ||
| 91 | * o Fixed freeing up of buffers using kfree() | ||
| 92 | * when packets are received. | ||
| 93 | * Jul 07, 1997 Jaspreet Singh o Added configurable TTL for UDP packets | ||
| 94 | * o Added ability to discard multicast and | ||
| 95 | * broadcast source addressed packets | ||
| 96 | * Jun 27, 1997 Jaspreet Singh o Added FT1 monitor capabilities | ||
| 97 | * New case (0x44) statement in if_send routine | ||
| 98 | * Added a global variable rCount to keep track | ||
| 99 | * of FT1 status enabled on the board. | ||
| 100 | * May 29, 1997 Jaspreet Singh o Fixed major Flow Control Problem | ||
| 101 | * With multiple boards a problem was seen where | ||
| 102 | * the second board always stopped transmitting | ||
| 103 | * packet after running for a while. The code | ||
| 104 | * got into a stage where the interrupts were | ||
| 105 | * disabled and dev->tbusy was set to 1. | ||
| 106 | * This caused the If_send() routine to get into | ||
| 107 | * the if clause for it(0,dev->tbusy) | ||
| 108 | * forever. | ||
| 109 | * The code got into this stage due to an | ||
| 110 | * interrupt occurring within the if clause for | ||
| 111 | * set_bit(0,dev->tbusy). Since an interrupt | ||
| 112 | * disables furhter transmit interrupt and | ||
| 113 | * makes dev->tbusy = 0, this effect was undone | ||
| 114 | * by making dev->tbusy = 1 in the if clause. | ||
| 115 | * The Fix checks to see if Transmit interrupts | ||
| 116 | * are disabled then do not make dev->tbusy = 1 | ||
| 117 | * Introduced a global variable: int_occur and | ||
| 118 | * added tx_int_enabled in the wan_device | ||
| 119 | * structure. | ||
| 120 | * May 21, 1997 Jaspreet Singh o Fixed UDP Management for multiple | ||
| 121 | * boards. | ||
| 122 | * | ||
| 123 | * Apr 25, 1997 Farhan Thawar o added UDP Management stuff | ||
| 124 | * o fixed bug in if_send() and tx_intr() to | ||
| 125 | * sleep and wakeup all devices | ||
| 126 | * Mar 11, 1997 Farhan Thawar Version 3.1.1 | ||
| 127 | * o fixed (+1) bug in fr508_rx_intr() | ||
| 128 | * o changed if_send() to return 0 if | ||
| 129 | * wandev.critical() is true | ||
| 130 | * o free socket buffer in if_send() if | ||
| 131 | * returning 0 | ||
| 132 | * o added tx_intr() routine | ||
| 133 | * Jan 30, 1997 Gene Kozin Version 3.1.0 | ||
| 134 | * o implemented exec() entry point | ||
| 135 | * o fixed a bug causing driver configured as | ||
| 136 | * a FR switch to be stuck in WAN_ | ||
| 137 | * mode | ||
| 138 | * Jan 02, 1997 Gene Kozin Initial version. | ||
| 139 | *****************************************************************************/ | ||
| 140 | |||
| 141 | #include <linux/module.h> | ||
| 142 | #include <linux/kernel.h> /* printk(), and other useful stuff */ | ||
| 143 | #include <linux/stddef.h> /* offsetof(), etc. */ | ||
| 144 | #include <linux/errno.h> /* return codes */ | ||
| 145 | #include <linux/string.h> /* inline memset(), etc. */ | ||
| 146 | #include <linux/slab.h> /* kmalloc(), kfree() */ | ||
| 147 | #include <linux/wanrouter.h> /* WAN router definitions */ | ||
| 148 | #include <linux/wanpipe.h> /* WANPIPE common user API definitions */ | ||
| 149 | #include <linux/workqueue.h> | ||
| 150 | #include <linux/if_arp.h> /* ARPHRD_* defines */ | ||
| 151 | #include <asm/byteorder.h> /* htons(), etc. */ | ||
| 152 | #include <asm/io.h> /* for inb(), outb(), etc. */ | ||
| 153 | #include <linux/time.h> /* for do_gettimeofday */ | ||
| 154 | #include <linux/in.h> /* sockaddr_in */ | ||
| 155 | #include <linux/jiffies.h> /* time_after() macro */ | ||
| 156 | #include <asm/errno.h> | ||
| 157 | |||
| 158 | #include <linux/ip.h> | ||
| 159 | #include <linux/if.h> | ||
| 160 | |||
| 161 | #include <linux/if_wanpipe_common.h> /* Wanpipe Socket */ | ||
| 162 | #include <linux/if_wanpipe.h> | ||
| 163 | |||
| 164 | #include <linux/sdla_fr.h> /* frame relay firmware API definitions */ | ||
| 165 | |||
| 166 | #include <asm/uaccess.h> | ||
| 167 | #include <linux/inetdevice.h> | ||
| 168 | #include <linux/netdevice.h> | ||
| 169 | |||
| 170 | #include <net/route.h> /* Dynamic Route Creation */ | ||
| 171 | #include <linux/etherdevice.h> /* eth_type_trans() used for bridging */ | ||
| 172 | #include <linux/random.h> | ||
| 173 | |||
| 174 | /****** Defines & Macros ****************************************************/ | ||
| 175 | |||
| 176 | #define MAX_CMD_RETRY 10 /* max number of firmware retries */ | ||
| 177 | |||
| 178 | #define FR_HEADER_LEN 8 /* max encapsulation header size */ | ||
| 179 | #define FR_CHANNEL_MTU 1500 /* unfragmented logical channel MTU */ | ||
| 180 | |||
| 181 | /* Q.922 frame types */ | ||
| 182 | #define Q922_UI 0x03 /* Unnumbered Info frame */ | ||
| 183 | #define Q922_XID 0xAF | ||
| 184 | |||
| 185 | /* DLCI configured or not */ | ||
| 186 | #define DLCI_NOT_CONFIGURED 0x00 | ||
| 187 | #define DLCI_CONFIG_PENDING 0x01 | ||
| 188 | #define DLCI_CONFIGURED 0x02 | ||
| 189 | |||
| 190 | /* CIR enabled or not */ | ||
| 191 | #define CIR_ENABLED 0x00 | ||
| 192 | #define CIR_DISABLED 0x01 | ||
| 193 | |||
| 194 | #define FRAME_RELAY_API 1 | ||
| 195 | #define MAX_BH_BUFF 10 | ||
| 196 | |||
| 197 | /* For handle_IPXWAN() */ | ||
| 198 | #define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) | ||
| 199 | |||
| 200 | /****** Data Structures *****************************************************/ | ||
| 201 | |||
| 202 | /* This is an extention of the 'struct device' we create for each network | ||
| 203 | * interface to keep the rest of channel-specific data. | ||
| 204 | */ | ||
| 205 | typedef struct fr_channel | ||
| 206 | { | ||
| 207 | wanpipe_common_t common; | ||
| 208 | char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ | ||
| 209 | unsigned dlci_configured ; /* check whether configured or not */ | ||
| 210 | unsigned cir_status; /* check whether CIR enabled or not */ | ||
| 211 | unsigned dlci; /* logical channel number */ | ||
| 212 | unsigned cir; /* committed information rate */ | ||
| 213 | unsigned bc; /* committed burst size */ | ||
| 214 | unsigned be; /* excess burst size */ | ||
| 215 | unsigned mc; /* multicast support on or off */ | ||
| 216 | unsigned tx_int_status; /* Transmit Interrupt Status */ | ||
| 217 | unsigned short pkt_length; /* Packet Length */ | ||
| 218 | unsigned long router_start_time;/* Router start time in seconds */ | ||
| 219 | unsigned long tick_counter; /* counter for transmit time out */ | ||
| 220 | char dev_pending_devtint; /* interface pending dev_tint() */ | ||
| 221 | void *dlci_int_interface; /* pointer to the DLCI Interface */ | ||
| 222 | unsigned long IB_addr; /* physical address of Interface Byte */ | ||
| 223 | unsigned long state_tick; /* time of the last state change */ | ||
| 224 | unsigned char enable_IPX; /* Enable/Disable the use of IPX */ | ||
| 225 | unsigned long network_number; /* Internal Network Number for IPX*/ | ||
| 226 | sdla_t *card; /* -> owner */ | ||
| 227 | unsigned route_flag; /* Add/Rem dest addr in route tables */ | ||
| 228 | unsigned inarp; /* Inverse Arp Request status */ | ||
| 229 | long inarp_ready; /* Ready to send requests */ | ||
| 230 | int inarp_interval; /* Time between InArp Requests */ | ||
| 231 | unsigned long inarp_tick; /* InArp jiffies tick counter */ | ||
| 232 | long interface_down; /* Bring interface down on disconnect */ | ||
| 233 | struct net_device_stats ifstats; /* interface statistics */ | ||
| 234 | if_send_stat_t drvstats_if_send; | ||
| 235 | rx_intr_stat_t drvstats_rx_intr; | ||
| 236 | pipe_mgmt_stat_t drvstats_gen; | ||
| 237 | unsigned long router_up_time; | ||
| 238 | |||
| 239 | unsigned short transmit_length; | ||
| 240 | struct sk_buff *delay_skb; | ||
| 241 | |||
| 242 | bh_data_t *bh_head; /* Circular buffer for chdlc_bh */ | ||
| 243 | unsigned long tq_working; | ||
| 244 | volatile int bh_write; | ||
| 245 | volatile int bh_read; | ||
| 246 | atomic_t bh_buff_used; | ||
| 247 | |||
| 248 | /* Polling task queue. Each interface | ||
| 249 | * has its own task queue, which is used | ||
| 250 | * to defer events from the interrupt */ | ||
| 251 | struct work_struct fr_poll_work; | ||
| 252 | struct timer_list fr_arp_timer; | ||
| 253 | |||
| 254 | u32 ip_local; | ||
| 255 | u32 ip_remote; | ||
| 256 | long config_dlci; | ||
| 257 | long unconfig_dlci; | ||
| 258 | |||
| 259 | /* Whether this interface should be setup as a gateway. | ||
| 260 | * Used by dynamic route setup code */ | ||
| 261 | u8 gateway; | ||
| 262 | |||
| 263 | /* True interface type */ | ||
| 264 | u8 true_if_encoding; | ||
| 265 | u8 fr_header[FR_HEADER_LEN]; | ||
| 266 | char fr_header_len; | ||
| 267 | |||
| 268 | } fr_channel_t; | ||
| 269 | |||
| 270 | /* Route Flag options */ | ||
| 271 | #define NO_ROUTE 0x00 | ||
| 272 | #define ADD_ROUTE 0x01 | ||
| 273 | #define ROUTE_ADDED 0x02 | ||
| 274 | #define REMOVE_ROUTE 0x03 | ||
| 275 | #define ARP_REQ 0x04 | ||
| 276 | |||
| 277 | /* inarp options */ | ||
| 278 | #define INARP_NONE 0x00 | ||
| 279 | #define INARP_REQUEST 0x01 | ||
| 280 | #define INARP_CONFIGURED 0x02 | ||
| 281 | |||
| 282 | /* reasons for enabling the timer interrupt on the adapter */ | ||
| 283 | #define TMR_INT_ENABLED_UDP 0x01 | ||
| 284 | #define TMR_INT_ENABLED_UPDATE 0x02 | ||
| 285 | #define TMR_INT_ENABLED_ARP 0x04 | ||
| 286 | #define TMR_INT_ENABLED_UPDATE_STATE 0x08 | ||
| 287 | #define TMR_INT_ENABLED_CONFIG 0x10 | ||
| 288 | #define TMR_INT_ENABLED_UNCONFIG 0x20 | ||
| 289 | |||
| 290 | |||
| 291 | typedef struct dlci_status | ||
| 292 | { | ||
| 293 | unsigned short dlci PACKED; | ||
| 294 | unsigned char state PACKED; | ||
| 295 | } dlci_status_t; | ||
| 296 | |||
| 297 | typedef struct dlci_IB_mapping | ||
| 298 | { | ||
| 299 | unsigned short dlci PACKED; | ||
| 300 | unsigned long addr_value PACKED; | ||
| 301 | } dlci_IB_mapping_t; | ||
| 302 | |||
| 303 | /* This structure is used for DLCI list Tx interrupt mode. It is used to | ||
| 304 | enable interrupt bit and set the packet length for transmission | ||
| 305 | */ | ||
| 306 | typedef struct fr_dlci_interface | ||
| 307 | { | ||
| 308 | unsigned char gen_interrupt PACKED; | ||
| 309 | unsigned short packet_length PACKED; | ||
| 310 | unsigned char reserved PACKED; | ||
| 311 | } fr_dlci_interface_t; | ||
| 312 | |||
| 313 | /* variable for keeping track of enabling/disabling FT1 monitor status */ | ||
| 314 | static int rCount = 0; | ||
| 315 | |||
| 316 | extern void disable_irq(unsigned int); | ||
| 317 | extern void enable_irq(unsigned int); | ||
| 318 | |||
| 319 | /* variable for keeping track of number of interrupts generated during | ||
| 320 | * interrupt test routine | ||
| 321 | */ | ||
| 322 | static int Intr_test_counter; | ||
| 323 | |||
| 324 | /****** Function Prototypes *************************************************/ | ||
| 325 | |||
| 326 | /* WAN link driver entry points. These are called by the WAN router module. */ | ||
| 327 | static int update(struct wan_device *wandev); | ||
| 328 | static int new_if(struct wan_device *wandev, struct net_device *dev, | ||
| 329 | wanif_conf_t *conf); | ||
| 330 | static int del_if(struct wan_device *wandev, struct net_device *dev); | ||
| 331 | static void disable_comm (sdla_t *card); | ||
| 332 | |||
| 333 | /* WANPIPE-specific entry points */ | ||
| 334 | static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data); | ||
| 335 | |||
| 336 | /* Network device interface */ | ||
| 337 | static int if_init(struct net_device *dev); | ||
| 338 | static int if_open(struct net_device *dev); | ||
| 339 | static int if_close(struct net_device *dev); | ||
| 340 | |||
| 341 | static void if_tx_timeout(struct net_device *dev); | ||
| 342 | |||
| 343 | static int if_rebuild_hdr (struct sk_buff *skb); | ||
| 344 | |||
| 345 | static int if_send(struct sk_buff *skb, struct net_device *dev); | ||
| 346 | static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, | ||
| 347 | struct sk_buff *skb); | ||
| 348 | static struct net_device_stats *if_stats(struct net_device *dev); | ||
| 349 | |||
| 350 | /* Interrupt handlers */ | ||
| 351 | static void fr_isr(sdla_t *card); | ||
| 352 | static void rx_intr(sdla_t *card); | ||
| 353 | static void tx_intr(sdla_t *card); | ||
| 354 | static void timer_intr(sdla_t *card); | ||
| 355 | static void spur_intr(sdla_t *card); | ||
| 356 | |||
| 357 | /* Frame relay firmware interface functions */ | ||
| 358 | static int fr_read_version(sdla_t *card, char *str); | ||
| 359 | static int fr_configure(sdla_t *card, fr_conf_t *conf); | ||
| 360 | static int fr_dlci_configure(sdla_t *card, fr_dlc_conf_t *conf, unsigned dlci); | ||
| 361 | static int fr_init_dlci (sdla_t *card, fr_channel_t *chan); | ||
| 362 | static int fr_set_intr_mode (sdla_t *card, unsigned mode, unsigned mtu, unsigned short timeout); | ||
| 363 | static int fr_comm_enable(sdla_t *card); | ||
| 364 | static void fr_comm_disable(sdla_t *card); | ||
| 365 | static int fr_get_err_stats(sdla_t *card); | ||
| 366 | static int fr_get_stats(sdla_t *card); | ||
| 367 | static int fr_add_dlci(sdla_t *card, int dlci); | ||
| 368 | static int fr_activate_dlci(sdla_t *card, int dlci); | ||
| 369 | static int fr_delete_dlci (sdla_t* card, int dlci); | ||
| 370 | static int fr_issue_isf(sdla_t *card, int isf); | ||
| 371 | static int fr_send(sdla_t *card, int dlci, unsigned char attr, int len, | ||
| 372 | void *buf); | ||
| 373 | static int fr_send_data_header(sdla_t *card, int dlci, unsigned char attr, int len, | ||
| 374 | void *buf,unsigned char hdr_len); | ||
| 375 | static unsigned int fr_send_hdr(sdla_t *card, int dlci, unsigned int offset); | ||
| 376 | |||
| 377 | static int check_dlci_config (sdla_t *card, fr_channel_t *chan); | ||
| 378 | static void initialize_rx_tx_buffers (sdla_t *card); | ||
| 379 | |||
| 380 | |||
| 381 | /* Firmware asynchronous event handlers */ | ||
| 382 | static int fr_event(sdla_t *card, int event, fr_mbox_t *mbox); | ||
| 383 | static int fr_modem_failure(sdla_t *card, fr_mbox_t *mbox); | ||
| 384 | static int fr_dlci_change(sdla_t *card, fr_mbox_t *mbox); | ||
| 385 | |||
| 386 | /* Miscellaneous functions */ | ||
| 387 | static int update_chan_state(struct net_device *dev); | ||
| 388 | static void set_chan_state(struct net_device *dev, int state); | ||
| 389 | static struct net_device *find_channel(sdla_t *card, unsigned dlci); | ||
| 390 | static int is_tx_ready(sdla_t *card, fr_channel_t *chan); | ||
| 391 | static unsigned int dec_to_uint(unsigned char *str, int len); | ||
| 392 | static int reply_udp( unsigned char *data, unsigned int mbox_len ); | ||
| 393 | |||
| 394 | static int intr_test( sdla_t* card ); | ||
| 395 | static void init_chan_statistics( fr_channel_t* chan ); | ||
| 396 | static void init_global_statistics( sdla_t* card ); | ||
| 397 | static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan ); | ||
| 398 | static int setup_for_delayed_transmit(struct net_device* dev, | ||
| 399 | struct sk_buff *skb); | ||
| 400 | |||
| 401 | struct net_device *move_dev_to_next(sdla_t *card, struct net_device *dev); | ||
| 402 | static int check_tx_status(sdla_t *card, struct net_device *dev); | ||
| 403 | |||
| 404 | /* Frame Relay Socket API */ | ||
| 405 | static void trigger_fr_bh (fr_channel_t *); | ||
| 406 | static void fr_bh(struct net_device *dev); | ||
| 407 | static int fr_bh_cleanup(struct net_device *dev); | ||
| 408 | static int bh_enqueue(struct net_device *dev, struct sk_buff *skb); | ||
| 409 | |||
| 410 | static void trigger_fr_poll(struct net_device *dev); | ||
| 411 | static void fr_poll(struct net_device *dev); | ||
| 412 | //static void add_gateway(struct net_device *dev); | ||
| 413 | |||
| 414 | static void trigger_unconfig_fr(struct net_device *dev); | ||
| 415 | static void unconfig_fr (sdla_t *); | ||
| 416 | |||
| 417 | static void trigger_config_fr (sdla_t *); | ||
| 418 | static void config_fr (sdla_t *); | ||
| 419 | |||
| 420 | |||
| 421 | /* Inverse ARP and Dynamic routing functions */ | ||
| 422 | int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct net_device *dev); | ||
| 423 | int is_arp(void *buf); | ||
| 424 | int send_inarp_request(sdla_t *card, struct net_device *dev); | ||
| 425 | |||
| 426 | static void trigger_fr_arp(struct net_device *dev); | ||
| 427 | static void fr_arp (unsigned long data); | ||
| 428 | |||
| 429 | |||
| 430 | /* Udp management functions */ | ||
| 431 | static int process_udp_mgmt_pkt(sdla_t *card); | ||
| 432 | static int udp_pkt_type( struct sk_buff *skb, sdla_t *card ); | ||
| 433 | static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card, | ||
| 434 | struct sk_buff *skb, int dlci); | ||
| 435 | |||
| 436 | /* IPX functions */ | ||
| 437 | static void switch_net_numbers(unsigned char *sendpacket, | ||
| 438 | unsigned long network_number, unsigned char incoming); | ||
| 439 | |||
| 440 | static int handle_IPXWAN(unsigned char *sendpacket, char *devname, | ||
| 441 | unsigned char enable_IPX, unsigned long network_number); | ||
| 442 | |||
| 443 | /* Lock Functions: SMP supported */ | ||
| 444 | void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags); | ||
| 445 | void s508_s514_lock(sdla_t *card, unsigned long *smp_flags); | ||
| 446 | |||
| 447 | unsigned short calc_checksum (char *, int); | ||
| 448 | static int setup_fr_header(struct sk_buff *skb, | ||
| 449 | struct net_device* dev, char op_mode); | ||
| 450 | |||
| 451 | |||
| 452 | /****** Public Functions ****************************************************/ | ||
| 453 | |||
| 454 | /*============================================================================ | ||
| 455 | * Frame relay protocol initialization routine. | ||
| 456 | * | ||
| 457 | * This routine is called by the main WANPIPE module during setup. At this | ||
| 458 | * point adapter is completely initialized and firmware is running. | ||
| 459 | * o read firmware version (to make sure it's alive) | ||
| 460 | * o configure adapter | ||
| 461 | * o initialize protocol-specific fields of the adapter data space. | ||
| 462 | * | ||
| 463 | * Return: 0 o.k. | ||
| 464 | * < 0 failure. | ||
| 465 | */ | ||
| 466 | int wpf_init(sdla_t *card, wandev_conf_t *conf) | ||
| 467 | { | ||
| 468 | |||
| 469 | int err; | ||
| 470 | fr508_flags_t* flags; | ||
| 471 | |||
| 472 | union | ||
| 473 | { | ||
| 474 | char str[80]; | ||
| 475 | fr_conf_t cfg; | ||
| 476 | } u; | ||
| 477 | |||
| 478 | fr_buf_info_t* buf_info; | ||
| 479 | int i; | ||
| 480 | |||
| 481 | |||
| 482 | printk(KERN_INFO "\n"); | ||
| 483 | |||
| 484 | /* Verify configuration ID */ | ||
| 485 | if (conf->config_id != WANCONFIG_FR) { | ||
| 486 | |||
| 487 | printk(KERN_INFO "%s: invalid configuration ID %u!\n", | ||
| 488 | card->devname, conf->config_id); | ||
| 489 | return -EINVAL; | ||
| 490 | |||
| 491 | } | ||
| 492 | |||
| 493 | /* Initialize protocol-specific fields of adapter data space */ | ||
| 494 | switch (card->hw.fwid) { | ||
| 495 | |||
| 496 | case SFID_FR508: | ||
| 497 | card->mbox = (void*)(card->hw.dpmbase + | ||
| 498 | FR508_MBOX_OFFS); | ||
| 499 | card->flags = (void*)(card->hw.dpmbase + | ||
| 500 | FR508_FLAG_OFFS); | ||
| 501 | if(card->hw.type == SDLA_S514) { | ||
| 502 | card->mbox += FR_MB_VECTOR; | ||
| 503 | card->flags += FR_MB_VECTOR; | ||
| 504 | } | ||
| 505 | card->isr = &fr_isr; | ||
| 506 | break; | ||
| 507 | |||
| 508 | default: | ||
| 509 | return -EINVAL; | ||
| 510 | } | ||
| 511 | |||
| 512 | flags = card->flags; | ||
| 513 | |||
| 514 | /* Read firmware version. Note that when adapter initializes, it | ||
| 515 | * clears the mailbox, so it may appear that the first command was | ||
| 516 | * executed successfully when in fact it was merely erased. To work | ||
| 517 | * around this, we execute the first command twice. | ||
| 518 | */ | ||
| 519 | |||
| 520 | if (fr_read_version(card, NULL) || fr_read_version(card, u.str)) | ||
| 521 | return -EIO; | ||
| 522 | |||
| 523 | printk(KERN_INFO "%s: running frame relay firmware v%s\n", | ||
| 524 | card->devname, u.str); | ||
| 525 | |||
| 526 | /* Adjust configuration */ | ||
| 527 | conf->mtu += FR_HEADER_LEN; | ||
| 528 | conf->mtu = (conf->mtu >= MIN_LGTH_FR_DATA_CFG) ? | ||
| 529 | min_t(unsigned int, conf->mtu, FR_MAX_NO_DATA_BYTES_IN_FRAME) : | ||
| 530 | FR_CHANNEL_MTU + FR_HEADER_LEN; | ||
| 531 | |||
| 532 | conf->bps = min_t(unsigned int, conf->bps, 2048000); | ||
| 533 | |||
| 534 | /* Initialze the configuration structure sent to the board to zero */ | ||
| 535 | memset(&u.cfg, 0, sizeof(u.cfg)); | ||
| 536 | |||
| 537 | memset(card->u.f.dlci_to_dev_map, 0, sizeof(card->u.f.dlci_to_dev_map)); | ||
| 538 | |||
| 539 | /* Configure adapter firmware */ | ||
| 540 | |||
| 541 | u.cfg.mtu = conf->mtu; | ||
| 542 | u.cfg.kbps = conf->bps / 1000; | ||
| 543 | |||
| 544 | u.cfg.cir_fwd = u.cfg.cir_bwd = 16; | ||
| 545 | u.cfg.bc_fwd = u.cfg.bc_bwd = 16; | ||
| 546 | |||
| 547 | u.cfg.options = 0x0000; | ||
| 548 | printk(KERN_INFO "%s: Global CIR enabled by Default\n", card->devname); | ||
| 549 | |||
| 550 | switch (conf->u.fr.signalling) { | ||
| 551 | |||
| 552 | case WANOPT_FR_ANSI: | ||
| 553 | u.cfg.options = 0x0000; | ||
| 554 | break; | ||
| 555 | |||
| 556 | case WANOPT_FR_Q933: | ||
| 557 | u.cfg.options |= 0x0200; | ||
| 558 | break; | ||
| 559 | |||
| 560 | case WANOPT_FR_LMI: | ||
| 561 | u.cfg.options |= 0x0400; | ||
| 562 | break; | ||
| 563 | |||
| 564 | case WANOPT_NO: | ||
| 565 | u.cfg.options |= 0x0800; | ||
| 566 | break; | ||
| 567 | default: | ||
| 568 | printk(KERN_INFO "%s: Illegal Signalling option\n", | ||
| 569 | card->wandev.name); | ||
| 570 | return -EINVAL; | ||
| 571 | } | ||
| 572 | |||
| 573 | |||
| 574 | card->wandev.signalling = conf->u.fr.signalling; | ||
| 575 | |||
| 576 | if (conf->station == WANOPT_CPE) { | ||
| 577 | |||
| 578 | |||
| 579 | if (conf->u.fr.signalling == WANOPT_NO){ | ||
| 580 | printk(KERN_INFO | ||
| 581 | "%s: ERROR - For NO signalling, station must be set to Node!", | ||
| 582 | card->devname); | ||
| 583 | return -EINVAL; | ||
| 584 | } | ||
| 585 | |||
| 586 | u.cfg.station = 0; | ||
| 587 | u.cfg.options |= 0x8000; /* auto config DLCI */ | ||
| 588 | card->u.f.dlci_num = 0; | ||
| 589 | |||
| 590 | } else { | ||
| 591 | |||
| 592 | u.cfg.station = 1; /* switch emulation mode */ | ||
| 593 | |||
| 594 | /* For switch emulation we have to create a list of dlci(s) | ||
| 595 | * that will be sent to be global SET_DLCI_CONFIGURATION | ||
| 596 | * command in fr_configure() routine. | ||
| 597 | */ | ||
| 598 | |||
| 599 | card->u.f.dlci_num = min_t(unsigned int, max_t(unsigned int, conf->u.fr.dlci_num, 1), 100); | ||
| 600 | |||
| 601 | for ( i = 0; i < card->u.f.dlci_num; i++) { | ||
| 602 | |||
| 603 | card->u.f.node_dlci[i] = (unsigned short) | ||
| 604 | conf->u.fr.dlci[i] ? conf->u.fr.dlci[i] : 16; | ||
| 605 | |||
| 606 | } | ||
| 607 | } | ||
| 608 | |||
| 609 | if (conf->clocking == WANOPT_INTERNAL) | ||
| 610 | u.cfg.port |= 0x0001; | ||
| 611 | |||
| 612 | if (conf->interface == WANOPT_RS232) | ||
| 613 | u.cfg.port |= 0x0002; | ||
| 614 | |||
| 615 | if (conf->u.fr.t391) | ||
| 616 | u.cfg.t391 = min_t(unsigned int, conf->u.fr.t391, 30); | ||
| 617 | else | ||
| 618 | u.cfg.t391 = 5; | ||
| 619 | |||
| 620 | if (conf->u.fr.t392) | ||
| 621 | u.cfg.t392 = min_t(unsigned int, conf->u.fr.t392, 30); | ||
| 622 | else | ||
| 623 | u.cfg.t392 = 15; | ||
| 624 | |||
| 625 | if (conf->u.fr.n391) | ||
| 626 | u.cfg.n391 = min_t(unsigned int, conf->u.fr.n391, 255); | ||
| 627 | else | ||
| 628 | u.cfg.n391 = 2; | ||
| 629 | |||
| 630 | if (conf->u.fr.n392) | ||
| 631 | u.cfg.n392 = min_t(unsigned int, conf->u.fr.n392, 10); | ||
| 632 | else | ||
| 633 | u.cfg.n392 = 3; | ||
| 634 | |||
| 635 | if (conf->u.fr.n393) | ||
| 636 | u.cfg.n393 = min_t(unsigned int, conf->u.fr.n393, 10); | ||
| 637 | else | ||
| 638 | u.cfg.n393 = 4; | ||
| 639 | |||
| 640 | if (fr_configure(card, &u.cfg)) | ||
| 641 | return -EIO; | ||
| 642 | |||
| 643 | if (card->hw.type == SDLA_S514) { | ||
| 644 | |||
| 645 | buf_info = (void*)(card->hw.dpmbase + FR_MB_VECTOR + | ||
| 646 | FR508_RXBC_OFFS); | ||
| 647 | |||
| 648 | card->rxmb = (void*)(buf_info->rse_next + card->hw.dpmbase); | ||
| 649 | |||
| 650 | card->u.f.rxmb_base = | ||
| 651 | (void*)(buf_info->rse_base + card->hw.dpmbase); | ||
| 652 | |||
| 653 | card->u.f.rxmb_last = | ||
| 654 | (void*)(buf_info->rse_base + | ||
| 655 | (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) + | ||
| 656 | card->hw.dpmbase); | ||
| 657 | }else{ | ||
| 658 | buf_info = (void*)(card->hw.dpmbase + FR508_RXBC_OFFS); | ||
| 659 | |||
| 660 | card->rxmb = (void*)(buf_info->rse_next - | ||
| 661 | FR_MB_VECTOR + card->hw.dpmbase); | ||
| 662 | |||
| 663 | card->u.f.rxmb_base = | ||
| 664 | (void*)(buf_info->rse_base - | ||
| 665 | FR_MB_VECTOR + card->hw.dpmbase); | ||
| 666 | |||
| 667 | card->u.f.rxmb_last = | ||
| 668 | (void*)(buf_info->rse_base + | ||
| 669 | (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) - | ||
| 670 | FR_MB_VECTOR + card->hw.dpmbase); | ||
| 671 | } | ||
| 672 | |||
| 673 | card->u.f.rx_base = buf_info->buf_base; | ||
| 674 | card->u.f.rx_top = buf_info->buf_top; | ||
| 675 | |||
| 676 | card->u.f.tx_interrupts_pending = 0; | ||
| 677 | |||
| 678 | card->wandev.mtu = conf->mtu; | ||
| 679 | card->wandev.bps = conf->bps; | ||
| 680 | card->wandev.interface = conf->interface; | ||
| 681 | card->wandev.clocking = conf->clocking; | ||
| 682 | card->wandev.station = conf->station; | ||
| 683 | card->poll = NULL; | ||
| 684 | card->exec = &wpf_exec; | ||
| 685 | card->wandev.update = &update; | ||
| 686 | card->wandev.new_if = &new_if; | ||
| 687 | card->wandev.del_if = &del_if; | ||
| 688 | card->wandev.state = WAN_DISCONNECTED; | ||
| 689 | card->wandev.ttl = conf->ttl; | ||
| 690 | card->wandev.udp_port = conf->udp_port; | ||
| 691 | card->disable_comm = &disable_comm; | ||
| 692 | card->u.f.arp_dev = NULL; | ||
| 693 | |||
| 694 | /* Intialize global statistics for a card */ | ||
| 695 | init_global_statistics( card ); | ||
| 696 | |||
| 697 | card->TracingEnabled = 0; | ||
| 698 | |||
| 699 | /* Interrupt Test */ | ||
| 700 | Intr_test_counter = 0; | ||
| 701 | card->intr_mode = INTR_TEST_MODE; | ||
| 702 | err = intr_test( card ); | ||
| 703 | |||
| 704 | printk(KERN_INFO "%s: End of Interrupt Test rc=0x%x count=%i\n", | ||
| 705 | card->devname,err,Intr_test_counter); | ||
| 706 | |||
| 707 | if (err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { | ||
| 708 | printk(KERN_ERR "%s: Interrupt Test Failed, Counter: %i\n", | ||
| 709 | card->devname, Intr_test_counter); | ||
| 710 | printk(KERN_ERR "Please choose another interrupt\n"); | ||
| 711 | err = -EIO; | ||
| 712 | return err; | ||
| 713 | } | ||
| 714 | |||
| 715 | printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", | ||
| 716 | card->devname, Intr_test_counter); | ||
| 717 | |||
| 718 | |||
| 719 | /* Apr 28 2000. Nenad Corbic | ||
| 720 | * Enable commnunications here, not in if_open or new_if, since | ||
| 721 | * interfaces come down when the link is disconnected. | ||
| 722 | */ | ||
| 723 | |||
| 724 | /* If you enable comms and then set ints, you get a Tx int as you | ||
| 725 | * perform the SET_INT_TRIGGERS command. So, we only set int | ||
| 726 | * triggers and then adjust the interrupt mask (to disable Tx ints) | ||
| 727 | * before enabling comms. | ||
| 728 | */ | ||
| 729 | if (fr_set_intr_mode(card, (FR_INTR_RXRDY | FR_INTR_TXRDY | | ||
| 730 | FR_INTR_DLC | FR_INTR_TIMER | FR_INTR_TX_MULT_DLCIs) , | ||
| 731 | card->wandev.mtu, 0)) { | ||
| 732 | return -EIO; | ||
| 733 | } | ||
| 734 | |||
| 735 | flags->imask &= ~(FR_INTR_TXRDY | FR_INTR_TIMER); | ||
| 736 | |||
| 737 | if (fr_comm_enable(card)) { | ||
| 738 | return -EIO; | ||
| 739 | } | ||
| 740 | wanpipe_set_state(card, WAN_CONNECTED); | ||
| 741 | spin_lock_init(&card->u.f.if_send_lock); | ||
| 742 | |||
| 743 | printk(KERN_INFO "\n"); | ||
| 744 | |||
| 745 | return 0; | ||
| 746 | } | ||
| 747 | |||
| 748 | /******* WAN Device Driver Entry Points *************************************/ | ||
| 749 | |||
| 750 | /*============================================================================ | ||
| 751 | * Update device status & statistics. | ||
| 752 | */ | ||
| 753 | static int update(struct wan_device* wandev) | ||
| 754 | { | ||
| 755 | volatile sdla_t* card; | ||
| 756 | unsigned long timeout; | ||
| 757 | fr508_flags_t* flags; | ||
| 758 | |||
| 759 | /* sanity checks */ | ||
| 760 | if ((wandev == NULL) || (wandev->private == NULL)) | ||
| 761 | return -EFAULT; | ||
| 762 | |||
| 763 | if (wandev->state == WAN_UNCONFIGURED) | ||
| 764 | return -ENODEV; | ||
| 765 | |||
| 766 | card = wandev->private; | ||
| 767 | flags = card->flags; | ||
| 768 | |||
| 769 | |||
| 770 | card->u.f.update_comms_stats = 1; | ||
| 771 | card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UPDATE; | ||
| 772 | flags->imask |= FR_INTR_TIMER; | ||
| 773 | timeout = jiffies; | ||
| 774 | for(;;) { | ||
| 775 | if(card->u.f.update_comms_stats == 0) | ||
| 776 | break; | ||
| 777 | if (time_after(jiffies, timeout + 1 * HZ)){ | ||
| 778 | card->u.f.update_comms_stats = 0; | ||
| 779 | return -EAGAIN; | ||
| 780 | } | ||
| 781 | } | ||
| 782 | |||
| 783 | return 0; | ||
| 784 | } | ||
| 785 | |||
| 786 | /*============================================================================ | ||
| 787 | * Create new logical channel. | ||
| 788 | * This routine is called by the router when ROUTER_IFNEW IOCTL is being | ||
| 789 | * handled. | ||
| 790 | * o parse media- and hardware-specific configuration | ||
| 791 | * o make sure that a new channel can be created | ||
| 792 | * o allocate resources, if necessary | ||
| 793 | * o prepare network device structure for registaration. | ||
| 794 | * | ||
| 795 | * Return: 0 o.k. | ||
| 796 | * < 0 failure (channel will not be created) | ||
| 797 | */ | ||
| 798 | static int new_if(struct wan_device* wandev, struct net_device* dev, | ||
| 799 | wanif_conf_t* conf) | ||
| 800 | { | ||
| 801 | sdla_t* card = wandev->private; | ||
| 802 | fr_channel_t* chan; | ||
| 803 | int dlci = 0; | ||
| 804 | int err = 0; | ||
| 805 | |||
| 806 | |||
| 807 | if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { | ||
| 808 | |||
| 809 | printk(KERN_INFO "%s: Invalid interface name!\n", | ||
| 810 | card->devname); | ||
| 811 | return -EINVAL; | ||
| 812 | } | ||
| 813 | |||
| 814 | /* allocate and initialize private data */ | ||
| 815 | chan = kmalloc(sizeof(fr_channel_t), GFP_KERNEL); | ||
| 816 | |||
| 817 | if (chan == NULL) | ||
| 818 | return -ENOMEM; | ||
| 819 | |||
| 820 | memset(chan, 0, sizeof(fr_channel_t)); | ||
| 821 | strcpy(chan->name, conf->name); | ||
| 822 | chan->card = card; | ||
| 823 | |||
| 824 | /* verify media address */ | ||
| 825 | if (isdigit(conf->addr[0])) { | ||
| 826 | |||
| 827 | dlci = dec_to_uint(conf->addr, 0); | ||
| 828 | |||
| 829 | if (dlci && (dlci <= HIGHEST_VALID_DLCI)) { | ||
| 830 | |||
| 831 | chan->dlci = dlci; | ||
| 832 | |||
| 833 | } else { | ||
| 834 | |||
| 835 | printk(KERN_ERR | ||
| 836 | "%s: Invalid DLCI %u on interface %s!\n", | ||
| 837 | wandev->name, dlci, chan->name); | ||
| 838 | err = -EINVAL; | ||
| 839 | } | ||
| 840 | |||
| 841 | } else { | ||
| 842 | printk(KERN_ERR | ||
| 843 | "%s: Invalid media address on interface %s!\n", | ||
| 844 | wandev->name, chan->name); | ||
| 845 | err = -EINVAL; | ||
| 846 | } | ||
| 847 | |||
| 848 | if ((chan->true_if_encoding = conf->true_if_encoding) == WANOPT_YES){ | ||
| 849 | printk(KERN_INFO | ||
| 850 | "%s: Enabling, true interface type encoding.\n", | ||
| 851 | card->devname); | ||
| 852 | } | ||
| 853 | |||
| 854 | |||
| 855 | |||
| 856 | /* Setup wanpipe as a router (WANPIPE) even if it is | ||
| 857 | * a bridged DLCI, or as an API | ||
| 858 | */ | ||
| 859 | if (strcmp(conf->usedby, "WANPIPE") == 0 || | ||
| 860 | strcmp(conf->usedby, "BRIDGE") == 0 || | ||
| 861 | strcmp(conf->usedby, "BRIDGE_N") == 0){ | ||
| 862 | |||
| 863 | if(strcmp(conf->usedby, "WANPIPE") == 0){ | ||
| 864 | chan->common.usedby = WANPIPE; | ||
| 865 | |||
| 866 | printk(KERN_INFO "%s: Running in WANPIPE mode.\n", | ||
| 867 | card->devname); | ||
| 868 | |||
| 869 | }else if(strcmp(conf->usedby, "BRIDGE") == 0){ | ||
| 870 | |||
| 871 | chan->common.usedby = BRIDGE; | ||
| 872 | |||
| 873 | printk(KERN_INFO "%s: Running in WANPIPE (BRIDGE) mode.\n", | ||
| 874 | card->devname); | ||
| 875 | }else if( strcmp(conf->usedby, "BRIDGE_N") == 0 ){ | ||
| 876 | |||
| 877 | chan->common.usedby = BRIDGE_NODE; | ||
| 878 | |||
| 879 | printk(KERN_INFO "%s: Running in WANPIPE (BRIDGE_NODE) mode.\n", | ||
| 880 | card->devname); | ||
| 881 | } | ||
| 882 | |||
| 883 | if (!err){ | ||
| 884 | /* Dynamic interface configuration option. | ||
| 885 | * On disconnect, if the options is selected, | ||
| 886 | * the interface will be brought down */ | ||
| 887 | if (conf->if_down == WANOPT_YES){ | ||
| 888 | set_bit(DYN_OPT_ON,&chan->interface_down); | ||
| 889 | printk(KERN_INFO | ||
| 890 | "%s: Dynamic interface configuration enabled.\n", | ||
| 891 | card->devname); | ||
| 892 | } | ||
| 893 | } | ||
| 894 | |||
| 895 | } else if(strcmp(conf->usedby, "API") == 0){ | ||
| 896 | |||
| 897 | chan->common.usedby = API; | ||
| 898 | printk(KERN_INFO "%s: Running in API mode.\n", | ||
| 899 | wandev->name); | ||
| 900 | } | ||
| 901 | |||
| 902 | if (err) { | ||
| 903 | |||
| 904 | kfree(chan); | ||
| 905 | return err; | ||
| 906 | } | ||
| 907 | |||
| 908 | /* place cir,be,bc and other channel specific information into the | ||
| 909 | * chan structure | ||
| 910 | */ | ||
| 911 | if (conf->cir) { | ||
| 912 | |||
| 913 | chan->cir = max_t(unsigned int, 1, | ||
| 914 | min_t(unsigned int, conf->cir, 512)); | ||
| 915 | chan->cir_status = CIR_ENABLED; | ||
| 916 | |||
| 917 | |||
| 918 | /* If CIR is enabled, force BC to equal CIR | ||
| 919 | * this solves number of potential problems if CIR is | ||
| 920 | * set and BC is not | ||
| 921 | */ | ||
| 922 | chan->bc = chan->cir; | ||
| 923 | |||
| 924 | if (conf->be){ | ||
| 925 | chan->be = max_t(unsigned int, | ||
| 926 | 0, min_t(unsigned int, conf->be, 511)); | ||
| 927 | }else{ | ||
| 928 | conf->be = 0; | ||
| 929 | } | ||
| 930 | |||
| 931 | printk (KERN_INFO "%s: CIR enabled for DLCI %i \n", | ||
| 932 | wandev->name,chan->dlci); | ||
| 933 | printk (KERN_INFO "%s: CIR = %i ; BC = %i ; BE = %i\n", | ||
| 934 | wandev->name,chan->cir,chan->bc,chan->be); | ||
| 935 | |||
| 936 | |||
| 937 | }else{ | ||
| 938 | chan->cir_status = CIR_DISABLED; | ||
| 939 | printk (KERN_INFO "%s: CIR disabled for DLCI %i\n", | ||
| 940 | wandev->name,chan->dlci); | ||
| 941 | } | ||
| 942 | |||
| 943 | chan->mc = conf->mc; | ||
| 944 | |||
| 945 | if (conf->inarp == WANOPT_YES){ | ||
| 946 | printk(KERN_INFO "%s: Inverse ARP Support Enabled\n",card->devname); | ||
| 947 | chan->inarp = conf->inarp ? INARP_REQUEST : INARP_NONE; | ||
| 948 | chan->inarp_interval = conf->inarp_interval ? conf->inarp_interval : 10; | ||
| 949 | }else{ | ||
| 950 | printk(KERN_INFO "%s: Inverse ARP Support Disabled\n",card->devname); | ||
| 951 | chan->inarp = INARP_NONE; | ||
| 952 | chan->inarp_interval = 10; | ||
| 953 | } | ||
| 954 | |||
| 955 | |||
| 956 | chan->dlci_configured = DLCI_NOT_CONFIGURED; | ||
| 957 | |||
| 958 | |||
| 959 | /*FIXME: IPX disabled in this WANPIPE version */ | ||
| 960 | if (conf->enable_IPX == WANOPT_YES){ | ||
| 961 | printk(KERN_INFO "%s: ERROR - This version of WANPIPE doesn't support IPX\n", | ||
| 962 | card->devname); | ||
| 963 | kfree(chan); | ||
| 964 | return -EINVAL; | ||
| 965 | }else{ | ||
| 966 | chan->enable_IPX = WANOPT_NO; | ||
| 967 | } | ||
| 968 | |||
| 969 | if (conf->network_number){ | ||
| 970 | chan->network_number = conf->network_number; | ||
| 971 | }else{ | ||
| 972 | chan->network_number = 0xDEADBEEF; | ||
| 973 | } | ||
| 974 | |||
| 975 | chan->route_flag = NO_ROUTE; | ||
| 976 | |||
| 977 | init_chan_statistics(chan); | ||
| 978 | |||
| 979 | chan->transmit_length = 0; | ||
| 980 | |||
| 981 | /* prepare network device data space for registration */ | ||
| 982 | strcpy(dev->name,chan->name); | ||
| 983 | |||
| 984 | dev->init = &if_init; | ||
| 985 | dev->priv = chan; | ||
| 986 | |||
| 987 | /* Initialize FR Polling Task Queue | ||
| 988 | * We need a poll routine for each network | ||
| 989 | * interface. | ||
| 990 | */ | ||
| 991 | INIT_WORK(&chan->fr_poll_work, (void *)fr_poll, dev); | ||
| 992 | |||
| 993 | init_timer(&chan->fr_arp_timer); | ||
| 994 | chan->fr_arp_timer.data=(unsigned long)dev; | ||
| 995 | chan->fr_arp_timer.function = fr_arp; | ||
| 996 | |||
| 997 | wandev->new_if_cnt++; | ||
| 998 | |||
| 999 | /* Tells us that if this interface is a | ||
| 1000 | * gateway or not */ | ||
| 1001 | if ((chan->gateway = conf->gateway) == WANOPT_YES){ | ||
| 1002 | printk(KERN_INFO "%s: Interface %s is set as a gateway.\n", | ||
| 1003 | card->devname,dev->name); | ||
| 1004 | } | ||
| 1005 | |||
| 1006 | /* M. Grant Patch Apr 28 2000 | ||
| 1007 | * Disallow duplicate dlci configurations. */ | ||
| 1008 | if (card->u.f.dlci_to_dev_map[chan->dlci] != NULL) { | ||
| 1009 | kfree(chan); | ||
| 1010 | return -EBUSY; | ||
| 1011 | } | ||
| 1012 | |||
| 1013 | /* Configure this dlci at a later date, when | ||
| 1014 | * the interface comes up. i.e. when if_open() | ||
| 1015 | * executes */ | ||
| 1016 | set_bit(0,&chan->config_dlci); | ||
| 1017 | |||
| 1018 | printk(KERN_INFO "\n"); | ||
| 1019 | |||
| 1020 | return 0; | ||
| 1021 | } | ||
| 1022 | |||
| 1023 | /*============================================================================ | ||
| 1024 | * Delete logical channel. | ||
| 1025 | */ | ||
| 1026 | static int del_if(struct wan_device* wandev, struct net_device* dev) | ||
| 1027 | { | ||
| 1028 | fr_channel_t* chan = dev->priv; | ||
| 1029 | unsigned long smp_flags=0; | ||
| 1030 | |||
| 1031 | /* This interface is dead, make sure the | ||
| 1032 | * ARP timer is stopped */ | ||
| 1033 | del_timer(&chan->fr_arp_timer); | ||
| 1034 | |||
| 1035 | /* If we are a NODE, we must unconfigure this DLCI | ||
| 1036 | * Trigger an unconfigure command that will | ||
| 1037 | * be executed in timer interrupt. We must wait | ||
| 1038 | * for the command to complete. */ | ||
| 1039 | trigger_unconfig_fr(dev); | ||
| 1040 | |||
| 1041 | lock_adapter_irq(&wandev->lock, &smp_flags); | ||
| 1042 | wandev->new_if_cnt--; | ||
| 1043 | unlock_adapter_irq(&wandev->lock, &smp_flags); | ||
| 1044 | |||
| 1045 | return 0; | ||
| 1046 | } | ||
| 1047 | |||
| 1048 | |||
| 1049 | /*===================================================================== | ||
| 1050 | * disable_comm | ||
| 1051 | * | ||
| 1052 | * Description: | ||
| 1053 | * Disable communications. | ||
| 1054 | * This code runs in shutdown (sdlamain.c) | ||
| 1055 | * under critical flag. Therefore it is not | ||
| 1056 | * necessary to set a critical flag here | ||
| 1057 | * | ||
| 1058 | * Usage: | ||
| 1059 | * Commnunications are disabled only on a card | ||
| 1060 | * shutdown. | ||
| 1061 | */ | ||
| 1062 | |||
| 1063 | static void disable_comm (sdla_t *card) | ||
| 1064 | { | ||
| 1065 | printk(KERN_INFO "%s: Disabling Communications!\n", | ||
| 1066 | card->devname); | ||
| 1067 | fr_comm_disable(card); | ||
| 1068 | } | ||
| 1069 | |||
| 1070 | /****** WANPIPE-specific entry points ***************************************/ | ||
| 1071 | |||
| 1072 | /*============================================================================ | ||
| 1073 | * Execute adapter interface command. | ||
| 1074 | */ | ||
| 1075 | static int wpf_exec (struct sdla* card, void* u_cmd, void* u_data) | ||
| 1076 | { | ||
| 1077 | fr_mbox_t* mbox = card->mbox; | ||
| 1078 | int retry = MAX_CMD_RETRY; | ||
| 1079 | int err, len; | ||
| 1080 | fr_cmd_t cmd; | ||
| 1081 | |||
| 1082 | if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd))) | ||
| 1083 | return -EFAULT; | ||
| 1084 | |||
| 1085 | /* execute command */ | ||
| 1086 | do | ||
| 1087 | { | ||
| 1088 | memcpy(&mbox->cmd, &cmd, sizeof(cmd)); | ||
| 1089 | |||
| 1090 | if (cmd.length){ | ||
| 1091 | if( copy_from_user((void*)&mbox->data, u_data, cmd.length)) | ||
| 1092 | return -EFAULT; | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | if (sdla_exec(mbox)) | ||
| 1096 | err = mbox->cmd.result; | ||
| 1097 | |||
| 1098 | else return -EIO; | ||
| 1099 | |||
| 1100 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
| 1101 | |||
| 1102 | /* return result */ | ||
| 1103 | if (copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(fr_cmd_t))) | ||
| 1104 | return -EFAULT; | ||
| 1105 | |||
| 1106 | len = mbox->cmd.length; | ||
| 1107 | |||
| 1108 | if (len && u_data && !copy_to_user(u_data, (void*)&mbox->data, len)) | ||
| 1109 | return -EFAULT; | ||
| 1110 | return 0; | ||
| 1111 | } | ||
| 1112 | |||
| 1113 | /****** Network Device Interface ********************************************/ | ||
| 1114 | |||
| 1115 | /*============================================================================ | ||
| 1116 | * Initialize Linux network interface. | ||
| 1117 | * | ||
| 1118 | * This routine is called only once for each interface, during Linux network | ||
| 1119 | * interface registration. Returning anything but zero will fail interface | ||
| 1120 | * registration. | ||
| 1121 | */ | ||
| 1122 | static int if_init(struct net_device* dev) | ||
| 1123 | { | ||
| 1124 | fr_channel_t* chan = dev->priv; | ||
| 1125 | sdla_t* card = chan->card; | ||
| 1126 | struct wan_device* wandev = &card->wandev; | ||
| 1127 | |||
| 1128 | /* Initialize device driver entry points */ | ||
| 1129 | dev->open = &if_open; | ||
| 1130 | dev->stop = &if_close; | ||
| 1131 | dev->hard_header = NULL; | ||
| 1132 | dev->rebuild_header = &if_rebuild_hdr; | ||
| 1133 | dev->hard_start_xmit = &if_send; | ||
| 1134 | dev->get_stats = &if_stats; | ||
| 1135 | dev->tx_timeout = &if_tx_timeout; | ||
| 1136 | dev->watchdog_timeo = TX_TIMEOUT; | ||
| 1137 | |||
| 1138 | if (chan->common.usedby == WANPIPE || chan->common.usedby == API){ | ||
| 1139 | |||
| 1140 | /* Initialize media-specific parameters */ | ||
| 1141 | if (chan->true_if_encoding){ | ||
| 1142 | dev->type = ARPHRD_DLCI; /* This breaks tcpdump */ | ||
| 1143 | }else{ | ||
| 1144 | dev->type = ARPHRD_PPP; /* ARP h/w type */ | ||
| 1145 | } | ||
| 1146 | |||
| 1147 | dev->flags |= IFF_POINTOPOINT; | ||
| 1148 | dev->flags |= IFF_NOARP; | ||
| 1149 | |||
| 1150 | /* Enable Multicast addressing */ | ||
| 1151 | if (chan->mc == WANOPT_YES){ | ||
| 1152 | dev->flags |= IFF_MULTICAST; | ||
| 1153 | } | ||
| 1154 | |||
| 1155 | dev->mtu = wandev->mtu - FR_HEADER_LEN; | ||
| 1156 | /* For an API, the maximum number of bytes that the stack will pass | ||
| 1157 | to the driver is (dev->mtu + dev->hard_header_len). So, adjust the | ||
| 1158 | mtu so that a frame of maximum size can be transmitted by the API. | ||
| 1159 | */ | ||
| 1160 | if(chan->common.usedby == API) { | ||
| 1161 | dev->mtu += (sizeof(api_tx_hdr_t) - FR_HEADER_LEN); | ||
| 1162 | } | ||
| 1163 | |||
| 1164 | dev->hard_header_len = FR_HEADER_LEN;/* media header length */ | ||
| 1165 | dev->addr_len = 2; /* hardware address length */ | ||
| 1166 | *(unsigned short*)dev->dev_addr = htons(chan->dlci); | ||
| 1167 | |||
| 1168 | /* Set transmit buffer queue length */ | ||
| 1169 | dev->tx_queue_len = 100; | ||
| 1170 | |||
| 1171 | }else{ | ||
| 1172 | |||
| 1173 | /* Setup the interface for Bridging */ | ||
| 1174 | int hw_addr=0; | ||
| 1175 | ether_setup(dev); | ||
| 1176 | |||
| 1177 | /* Use a random number to generate the MAC address */ | ||
| 1178 | memcpy(dev->dev_addr, "\xFE\xFC\x00\x00\x00\x00", 6); | ||
| 1179 | get_random_bytes(&hw_addr, sizeof(hw_addr)); | ||
| 1180 | *(int *)(dev->dev_addr + 2) += hw_addr; | ||
| 1181 | } | ||
| 1182 | |||
| 1183 | /* Initialize hardware parameters (just for reference) */ | ||
| 1184 | dev->irq = wandev->irq; | ||
| 1185 | dev->dma = wandev->dma; | ||
| 1186 | dev->base_addr = wandev->ioport; | ||
| 1187 | dev->mem_start = wandev->maddr; | ||
| 1188 | dev->mem_end = wandev->maddr + wandev->msize - 1; | ||
| 1189 | SET_MODULE_OWNER(dev); | ||
| 1190 | |||
| 1191 | return 0; | ||
| 1192 | } | ||
| 1193 | |||
| 1194 | /*============================================================================ | ||
| 1195 | * Open network interface. | ||
| 1196 | * o if this is the first open, then enable communications and interrupts. | ||
| 1197 | * o prevent module from unloading by incrementing use count | ||
| 1198 | * | ||
| 1199 | * Return 0 if O.k. or errno. | ||
| 1200 | */ | ||
| 1201 | static int if_open(struct net_device* dev) | ||
| 1202 | { | ||
| 1203 | fr_channel_t* chan = dev->priv; | ||
| 1204 | sdla_t* card = chan->card; | ||
| 1205 | int err = 0; | ||
| 1206 | struct timeval tv; | ||
| 1207 | |||
| 1208 | if (netif_running(dev)) | ||
| 1209 | return -EBUSY; | ||
| 1210 | |||
| 1211 | /* Initialize the task queue */ | ||
| 1212 | chan->tq_working=0; | ||
| 1213 | |||
| 1214 | INIT_WORK(&chan->common.wanpipe_work, (void *)fr_bh, dev); | ||
| 1215 | |||
| 1216 | /* Allocate and initialize BH circular buffer */ | ||
| 1217 | chan->bh_head = kmalloc((sizeof(bh_data_t)*MAX_BH_BUFF),GFP_ATOMIC); | ||
| 1218 | memset(chan->bh_head,0,(sizeof(bh_data_t)*MAX_BH_BUFF)); | ||
| 1219 | atomic_set(&chan->bh_buff_used, 0); | ||
| 1220 | |||
| 1221 | netif_start_queue(dev); | ||
| 1222 | |||
| 1223 | wanpipe_open(card); | ||
| 1224 | do_gettimeofday( &tv ); | ||
| 1225 | chan->router_start_time = tv.tv_sec; | ||
| 1226 | |||
| 1227 | if (test_bit(0,&chan->config_dlci)){ | ||
| 1228 | trigger_config_fr (card); | ||
| 1229 | }else if (chan->inarp == INARP_REQUEST){ | ||
| 1230 | trigger_fr_arp(dev); | ||
| 1231 | } | ||
| 1232 | |||
| 1233 | return err; | ||
| 1234 | } | ||
| 1235 | |||
| 1236 | /*============================================================================ | ||
| 1237 | * Close network interface. | ||
| 1238 | * o if this is the last open, then disable communications and interrupts. | ||
| 1239 | * o reset flags. | ||
| 1240 | */ | ||
| 1241 | static int if_close(struct net_device* dev) | ||
| 1242 | { | ||
| 1243 | fr_channel_t* chan = dev->priv; | ||
| 1244 | sdla_t* card = chan->card; | ||
| 1245 | |||
| 1246 | if (chan->inarp == INARP_CONFIGURED) { | ||
| 1247 | chan->inarp = INARP_REQUEST; | ||
| 1248 | } | ||
| 1249 | |||
| 1250 | netif_stop_queue(dev); | ||
| 1251 | wanpipe_close(card); | ||
| 1252 | |||
| 1253 | return 0; | ||
| 1254 | } | ||
| 1255 | |||
| 1256 | /*============================================================================ | ||
| 1257 | * Re-build media header. | ||
| 1258 | * | ||
| 1259 | * Return: 1 physical address resolved. | ||
| 1260 | * 0 physical address not resolved | ||
| 1261 | */ | ||
| 1262 | static int if_rebuild_hdr (struct sk_buff* skb) | ||
| 1263 | { | ||
| 1264 | struct net_device *dev = skb->dev; | ||
| 1265 | fr_channel_t* chan = dev->priv; | ||
| 1266 | sdla_t* card = chan->card; | ||
| 1267 | |||
| 1268 | printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", | ||
| 1269 | card->devname, dev->name); | ||
| 1270 | return 1; | ||
| 1271 | } | ||
| 1272 | |||
| 1273 | /*============================================================================ | ||
| 1274 | * Handle transmit timeout event from netif watchdog | ||
| 1275 | */ | ||
| 1276 | static void if_tx_timeout(struct net_device *dev) | ||
| 1277 | { | ||
| 1278 | fr_channel_t* chan = dev->priv; | ||
| 1279 | sdla_t *card = chan->card; | ||
| 1280 | |||
| 1281 | /* If our device stays busy for at least 5 seconds then we will | ||
| 1282 | * kick start the device by making dev->tbusy = 0. We expect | ||
| 1283 | * that our device never stays busy more than 5 seconds. So this | ||
| 1284 | * is only used as a last resort. | ||
| 1285 | */ | ||
| 1286 | |||
| 1287 | chan->drvstats_if_send.if_send_tbusy++; | ||
| 1288 | ++chan->ifstats.collisions; | ||
| 1289 | |||
| 1290 | printk (KERN_INFO "%s: Transmit timed out on %s\n", | ||
| 1291 | card->devname, dev->name); | ||
| 1292 | chan->drvstats_if_send.if_send_tbusy_timeout++; | ||
| 1293 | netif_wake_queue (dev); | ||
| 1294 | |||
| 1295 | } | ||
| 1296 | |||
| 1297 | |||
| 1298 | /*============================================================================ | ||
| 1299 | * Send a packet on a network interface. | ||
| 1300 | * o set tbusy flag (marks start of the transmission) to block a timer-based | ||
| 1301 | * transmit from overlapping. | ||
| 1302 | * o set critical flag when accessing board. | ||
| 1303 | * o check link state. If link is not up, then drop the packet. | ||
| 1304 | * o check channel status. If it's down then initiate a call. | ||
| 1305 | * o pass a packet to corresponding WAN device. | ||
| 1306 | * o free socket buffer | ||
| 1307 | * | ||
| 1308 | * Return: 0 complete (socket buffer must be freed) | ||
| 1309 | * non-0 packet may be re-transmitted (tbusy must be set) | ||
| 1310 | * | ||
| 1311 | * Notes: | ||
| 1312 | * 1. This routine is called either by the protocol stack or by the "net | ||
| 1313 | * bottom half" (with interrupts enabled). | ||
| 1314 | * | ||
| 1315 | * 2. Using netif_start_queue() and netif_stop_queue() | ||
| 1316 | * will inhibit further transmit requests from the protocol stack | ||
| 1317 | * and can be used for flow control with protocol layer. | ||
| 1318 | */ | ||
| 1319 | static int if_send(struct sk_buff* skb, struct net_device* dev) | ||
| 1320 | { | ||
| 1321 | fr_channel_t* chan = dev->priv; | ||
| 1322 | sdla_t* card = chan->card; | ||
| 1323 | int err; | ||
| 1324 | unsigned char *sendpacket; | ||
| 1325 | fr508_flags_t* adptr_flags = card->flags; | ||
| 1326 | int udp_type; | ||
| 1327 | long delay_tx_queued = 0; | ||
| 1328 | unsigned long smp_flags=0; | ||
| 1329 | unsigned char attr = 0; | ||
| 1330 | |||
| 1331 | chan->drvstats_if_send.if_send_entry++; | ||
| 1332 | |||
| 1333 | netif_stop_queue(dev); | ||
| 1334 | |||
| 1335 | if (skb == NULL) { | ||
| 1336 | /* if we get here, some higher layer thinks we've missed an | ||
| 1337 | * tx-done interrupt. | ||
| 1338 | */ | ||
| 1339 | printk(KERN_INFO "%s: interface %s got kicked!\n", | ||
| 1340 | card->devname, dev->name); | ||
| 1341 | chan->drvstats_if_send.if_send_skb_null ++; | ||
| 1342 | |||
| 1343 | netif_wake_queue(dev); | ||
| 1344 | return 0; | ||
| 1345 | } | ||
| 1346 | |||
| 1347 | /* If a peripheral task is running just drop packets */ | ||
| 1348 | if (test_bit(PERI_CRIT, &card->wandev.critical)){ | ||
| 1349 | |||
| 1350 | printk(KERN_INFO "%s: Critical in if_send(): Peripheral running!\n", | ||
| 1351 | card->devname); | ||
| 1352 | |||
| 1353 | dev_kfree_skb_any(skb); | ||
| 1354 | netif_start_queue(dev); | ||
| 1355 | return 0; | ||
| 1356 | } | ||
| 1357 | |||
| 1358 | /* We must set the 'tbusy' flag if we already have a packet queued for | ||
| 1359 | transmission in the transmit interrupt handler. However, we must | ||
| 1360 | ensure that the transmit interrupt does not reset the 'tbusy' flag | ||
| 1361 | just before we set it, as this will result in a "transmit timeout". | ||
| 1362 | */ | ||
| 1363 | set_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical); | ||
| 1364 | if(chan->transmit_length) { | ||
| 1365 | netif_stop_queue(dev); | ||
| 1366 | chan->tick_counter = jiffies; | ||
| 1367 | clear_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical); | ||
| 1368 | return 1; | ||
| 1369 | } | ||
| 1370 | clear_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical); | ||
| 1371 | |||
| 1372 | /* Move the if_header() code to here. By inserting frame | ||
| 1373 | * relay header in if_header() we would break the | ||
| 1374 | * tcpdump and other packet sniffers */ | ||
| 1375 | chan->fr_header_len = setup_fr_header(skb,dev,chan->common.usedby); | ||
| 1376 | if (chan->fr_header_len < 0 ){ | ||
| 1377 | ++chan->ifstats.tx_dropped; | ||
| 1378 | ++card->wandev.stats.tx_dropped; | ||
| 1379 | |||
| 1380 | dev_kfree_skb_any(skb); | ||
| 1381 | netif_start_queue(dev); | ||
| 1382 | return 0; | ||
| 1383 | } | ||
| 1384 | |||
| 1385 | sendpacket = skb->data; | ||
| 1386 | |||
| 1387 | udp_type = udp_pkt_type(skb, card); | ||
| 1388 | |||
| 1389 | if(udp_type != UDP_INVALID_TYPE) { | ||
| 1390 | if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, skb, | ||
| 1391 | chan->dlci)) { | ||
| 1392 | adptr_flags->imask |= FR_INTR_TIMER; | ||
| 1393 | if (udp_type == UDP_FPIPE_TYPE){ | ||
| 1394 | chan->drvstats_if_send. | ||
| 1395 | if_send_PIPE_request ++; | ||
| 1396 | } | ||
| 1397 | } | ||
| 1398 | netif_start_queue(dev); | ||
| 1399 | return 0; | ||
| 1400 | } | ||
| 1401 | |||
| 1402 | //FIXME: can we do better than sendpacket[2]? | ||
| 1403 | if ((chan->common.usedby == WANPIPE) && (sendpacket[2] == 0x45)) { | ||
| 1404 | |||
| 1405 | /* check to see if the source IP address is a broadcast or */ | ||
| 1406 | /* multicast IP address */ | ||
| 1407 | if(chk_bcast_mcast_addr(card, dev, skb)){ | ||
| 1408 | ++chan->ifstats.tx_dropped; | ||
| 1409 | ++card->wandev.stats.tx_dropped; | ||
| 1410 | dev_kfree_skb_any(skb); | ||
| 1411 | netif_start_queue(dev); | ||
| 1412 | return 0; | ||
| 1413 | } | ||
| 1414 | } | ||
| 1415 | |||
| 1416 | |||
| 1417 | /* Lock the S514/S508 card: SMP Supported */ | ||
| 1418 | s508_s514_lock(card,&smp_flags); | ||
| 1419 | |||
| 1420 | if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) { | ||
| 1421 | |||
| 1422 | chan->drvstats_if_send.if_send_critical_non_ISR ++; | ||
| 1423 | chan->ifstats.tx_dropped ++; | ||
| 1424 | printk(KERN_INFO "%s Critical in IF_SEND: if_send() already running!\n", | ||
| 1425 | card->devname); | ||
| 1426 | goto if_send_start_and_exit; | ||
| 1427 | } | ||
| 1428 | |||
| 1429 | /* API packet check: minimum packet size must be greater than | ||
| 1430 | * 16 byte API header */ | ||
| 1431 | if((chan->common.usedby == API) && (skb->len <= sizeof(api_tx_hdr_t))) { | ||
| 1432 | ++chan->ifstats.tx_dropped; | ||
| 1433 | ++card->wandev.stats.tx_dropped; | ||
| 1434 | |||
| 1435 | |||
| 1436 | goto if_send_start_and_exit; | ||
| 1437 | |||
| 1438 | }else{ | ||
| 1439 | /* During API transmission, get rid of the API header */ | ||
| 1440 | if (chan->common.usedby == API) { | ||
| 1441 | api_tx_hdr_t* api_tx_hdr; | ||
| 1442 | api_tx_hdr = (api_tx_hdr_t*)&skb->data[0x00]; | ||
| 1443 | attr = api_tx_hdr->attr; | ||
| 1444 | skb_pull(skb,sizeof(api_tx_hdr_t)); | ||
| 1445 | } | ||
| 1446 | } | ||
| 1447 | |||
| 1448 | if (card->wandev.state != WAN_CONNECTED) { | ||
| 1449 | chan->drvstats_if_send.if_send_wan_disconnected ++; | ||
| 1450 | ++chan->ifstats.tx_dropped; | ||
| 1451 | ++card->wandev.stats.tx_dropped; | ||
| 1452 | |||
| 1453 | } else if (chan->common.state != WAN_CONNECTED) { | ||
| 1454 | chan->drvstats_if_send.if_send_dlci_disconnected ++; | ||
| 1455 | |||
| 1456 | /* Update the DLCI state in timer interrupt */ | ||
| 1457 | card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UPDATE_STATE; | ||
| 1458 | adptr_flags->imask |= FR_INTR_TIMER; | ||
| 1459 | |||
| 1460 | ++chan->ifstats.tx_dropped; | ||
| 1461 | ++card->wandev.stats.tx_dropped; | ||
| 1462 | |||
| 1463 | } else if (!is_tx_ready(card, chan)) { | ||
| 1464 | /* No tx buffers available, store for delayed transmit */ | ||
| 1465 | if (!setup_for_delayed_transmit(dev, skb)){ | ||
| 1466 | set_bit(1,&delay_tx_queued); | ||
| 1467 | } | ||
| 1468 | chan->drvstats_if_send.if_send_no_bfrs++; | ||
| 1469 | |||
| 1470 | } else if (!skb->protocol) { | ||
| 1471 | /* No protocols drop packet */ | ||
| 1472 | chan->drvstats_if_send.if_send_protocol_error ++; | ||
| 1473 | ++card->wandev.stats.tx_errors; | ||
| 1474 | |||
| 1475 | } else if (test_bit(ARP_CRIT,&card->wandev.critical)){ | ||
| 1476 | /* We are trying to send an ARP Packet, block IP data until | ||
| 1477 | * ARP is sent */ | ||
| 1478 | ++chan->ifstats.tx_dropped; | ||
| 1479 | ++card->wandev.stats.tx_dropped; | ||
| 1480 | |||
| 1481 | } else { | ||
| 1482 | //FIXME: IPX is not implemented in this version of Frame Relay ? | ||
| 1483 | if((chan->common.usedby == WANPIPE) && | ||
| 1484 | sendpacket[1] == 0x00 && | ||
| 1485 | sendpacket[2] == 0x80 && | ||
| 1486 | sendpacket[6] == 0x81 && | ||
| 1487 | sendpacket[7] == 0x37) { | ||
| 1488 | |||
| 1489 | if( chan->enable_IPX ) { | ||
| 1490 | switch_net_numbers(sendpacket, | ||
| 1491 | chan->network_number, 0); | ||
| 1492 | } else { | ||
| 1493 | //FIXME: Take this out when IPX is fixed | ||
| 1494 | printk(KERN_INFO | ||
| 1495 | "%s: WARNING: Unsupported IPX data in send, packet dropped\n", | ||
| 1496 | card->devname); | ||
| 1497 | } | ||
| 1498 | |||
| 1499 | }else{ | ||
| 1500 | err = fr_send_data_header(card, chan->dlci, attr, skb->len, skb->data, chan->fr_header_len); | ||
| 1501 | if (err) { | ||
| 1502 | switch(err) { | ||
| 1503 | case FRRES_CIR_OVERFLOW: | ||
| 1504 | case FRRES_BUFFER_OVERFLOW: | ||
| 1505 | if (!setup_for_delayed_transmit(dev, skb)){ | ||
| 1506 | set_bit(1,&delay_tx_queued); | ||
| 1507 | } | ||
| 1508 | chan->drvstats_if_send. | ||
| 1509 | if_send_adptr_bfrs_full ++; | ||
| 1510 | break; | ||
| 1511 | |||
| 1512 | case FRRES_TOO_LONG: | ||
| 1513 | if (net_ratelimit()){ | ||
| 1514 | printk(KERN_INFO | ||
| 1515 | "%s: Error: Frame too long, transmission failed %i\n", | ||
| 1516 | card->devname, (unsigned int)skb->len); | ||
| 1517 | } | ||
| 1518 | /* Drop down to default */ | ||
| 1519 | default: | ||
| 1520 | chan->drvstats_if_send. | ||
| 1521 | if_send_dlci_disconnected ++; | ||
| 1522 | ++chan->ifstats.tx_dropped; | ||
| 1523 | ++card->wandev.stats.tx_dropped; | ||
| 1524 | break; | ||
| 1525 | } | ||
| 1526 | } else { | ||
| 1527 | chan->drvstats_if_send. | ||
| 1528 | if_send_bfr_passed_to_adptr++; | ||
| 1529 | ++chan->ifstats.tx_packets; | ||
| 1530 | ++card->wandev.stats.tx_packets; | ||
| 1531 | |||
| 1532 | chan->ifstats.tx_bytes += skb->len; | ||
| 1533 | card->wandev.stats.tx_bytes += skb->len; | ||
| 1534 | dev->trans_start = jiffies; | ||
| 1535 | } | ||
| 1536 | } | ||
| 1537 | } | ||
| 1538 | |||
| 1539 | if_send_start_and_exit: | ||
| 1540 | |||
| 1541 | netif_start_queue(dev); | ||
| 1542 | |||
| 1543 | /* If we queued the packet for transmission, we must not | ||
| 1544 | * deallocate it. The packet is unlinked from the IP stack | ||
| 1545 | * not copied. Therefore, we must keep the original packet */ | ||
| 1546 | if (!test_bit(1,&delay_tx_queued)) { | ||
| 1547 | dev_kfree_skb_any(skb); | ||
| 1548 | }else{ | ||
| 1549 | adptr_flags->imask |= FR_INTR_TXRDY; | ||
| 1550 | card->u.f.tx_interrupts_pending ++; | ||
| 1551 | } | ||
| 1552 | |||
| 1553 | clear_bit(SEND_CRIT, (void*)&card->wandev.critical); | ||
| 1554 | |||
| 1555 | s508_s514_unlock(card,&smp_flags); | ||
| 1556 | |||
| 1557 | return 0; | ||
| 1558 | } | ||
| 1559 | |||
| 1560 | |||
| 1561 | |||
| 1562 | /*============================================================================ | ||
| 1563 | * Setup so that a frame can be transmitted on the occurrence of a transmit | ||
| 1564 | * interrupt. | ||
| 1565 | */ | ||
| 1566 | static int setup_for_delayed_transmit(struct net_device* dev, | ||
| 1567 | struct sk_buff *skb) | ||
| 1568 | { | ||
| 1569 | fr_channel_t* chan = dev->priv; | ||
| 1570 | sdla_t* card = chan->card; | ||
| 1571 | fr_dlci_interface_t* dlci_interface; | ||
| 1572 | int len = skb->len; | ||
| 1573 | |||
| 1574 | /* Check that the dlci is properly configured, | ||
| 1575 | * before using tx interrupt */ | ||
| 1576 | if (!chan->dlci_int_interface){ | ||
| 1577 | if (net_ratelimit()){ | ||
| 1578 | printk(KERN_INFO | ||
| 1579 | "%s: ERROR on DLCI %i: Not configured properly !\n", | ||
| 1580 | card->devname, chan->dlci); | ||
| 1581 | printk(KERN_INFO "%s: Please contact Sangoma Technologies\n", | ||
| 1582 | card->devname); | ||
| 1583 | } | ||
| 1584 | return 1; | ||
| 1585 | } | ||
| 1586 | |||
| 1587 | dlci_interface = chan->dlci_int_interface; | ||
| 1588 | |||
| 1589 | if(chan->transmit_length) { | ||
| 1590 | printk(KERN_INFO "%s: Big mess in setup_for_del...\n", | ||
| 1591 | card->devname); | ||
| 1592 | return 1; | ||
| 1593 | } | ||
| 1594 | |||
| 1595 | if(len > FR_MAX_NO_DATA_BYTES_IN_FRAME) { | ||
| 1596 | //FIXME: increment some statistic */ | ||
| 1597 | return 1; | ||
| 1598 | } | ||
| 1599 | |||
| 1600 | chan->transmit_length = len; | ||
| 1601 | chan->delay_skb = skb; | ||
| 1602 | |||
| 1603 | dlci_interface->gen_interrupt |= FR_INTR_TXRDY; | ||
| 1604 | dlci_interface->packet_length = len; | ||
| 1605 | |||
| 1606 | /* Turn on TX interrupt at the end of if_send */ | ||
| 1607 | return 0; | ||
| 1608 | } | ||
| 1609 | |||
| 1610 | |||
| 1611 | /*============================================================================ | ||
| 1612 | * Check to see if the packet to be transmitted contains a broadcast or | ||
| 1613 | * multicast source IP address. | ||
| 1614 | * Return 0 if not broadcast/multicast address, otherwise return 1. | ||
| 1615 | */ | ||
| 1616 | |||
| 1617 | static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, | ||
| 1618 | struct sk_buff *skb) | ||
| 1619 | { | ||
| 1620 | u32 src_ip_addr; | ||
| 1621 | u32 broadcast_ip_addr = 0; | ||
| 1622 | struct in_device *in_dev; | ||
| 1623 | fr_channel_t* chan = dev->priv; | ||
| 1624 | |||
| 1625 | /* read the IP source address from the outgoing packet */ | ||
| 1626 | src_ip_addr = *(u32 *)(skb->data + 14); | ||
| 1627 | |||
| 1628 | /* read the IP broadcast address for the device */ | ||
| 1629 | in_dev = dev->ip_ptr; | ||
| 1630 | if(in_dev != NULL) { | ||
| 1631 | struct in_ifaddr *ifa= in_dev->ifa_list; | ||
| 1632 | if(ifa != NULL) | ||
| 1633 | broadcast_ip_addr = ifa->ifa_broadcast; | ||
| 1634 | else | ||
| 1635 | return 0; | ||
| 1636 | } | ||
| 1637 | |||
| 1638 | /* check if the IP Source Address is a Broadcast address */ | ||
| 1639 | if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { | ||
| 1640 | printk(KERN_INFO | ||
| 1641 | "%s: Broadcast Source Address silently discarded\n", | ||
| 1642 | card->devname); | ||
| 1643 | return 1; | ||
| 1644 | } | ||
| 1645 | |||
| 1646 | /* check if the IP Source Address is a Multicast address */ | ||
| 1647 | if((chan->mc == WANOPT_NO) && (ntohl(src_ip_addr) >= 0xE0000001) && | ||
| 1648 | (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { | ||
| 1649 | printk(KERN_INFO | ||
| 1650 | "%s: Multicast Source Address silently discarded\n", | ||
| 1651 | card->devname); | ||
| 1652 | return 1; | ||
| 1653 | } | ||
| 1654 | |||
| 1655 | return 0; | ||
| 1656 | } | ||
| 1657 | |||
| 1658 | /*============================================================================ | ||
| 1659 | * Reply to UDP Management system. | ||
| 1660 | * Return nothing. | ||
| 1661 | */ | ||
| 1662 | static int reply_udp( unsigned char *data, unsigned int mbox_len ) | ||
| 1663 | { | ||
| 1664 | unsigned short len, udp_length, temp, ip_length; | ||
| 1665 | unsigned long ip_temp; | ||
| 1666 | int even_bound = 0; | ||
| 1667 | |||
| 1668 | |||
| 1669 | fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)data; | ||
| 1670 | |||
| 1671 | /* Set length of packet */ | ||
| 1672 | len = //sizeof(fr_encap_hdr_t)+ | ||
| 1673 | sizeof(ip_pkt_t)+ | ||
| 1674 | sizeof(udp_pkt_t)+ | ||
| 1675 | sizeof(wp_mgmt_t)+ | ||
| 1676 | sizeof(cblock_t)+ | ||
| 1677 | mbox_len; | ||
| 1678 | |||
| 1679 | |||
| 1680 | /* fill in UDP reply */ | ||
| 1681 | fr_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; | ||
| 1682 | |||
| 1683 | /* fill in UDP length */ | ||
| 1684 | udp_length = sizeof(udp_pkt_t)+ | ||
| 1685 | sizeof(wp_mgmt_t)+ | ||
| 1686 | sizeof(cblock_t)+ | ||
| 1687 | mbox_len; | ||
| 1688 | |||
| 1689 | |||
| 1690 | /* put it on an even boundary */ | ||
| 1691 | if ( udp_length & 0x0001 ) { | ||
| 1692 | udp_length += 1; | ||
| 1693 | len += 1; | ||
| 1694 | even_bound = 1; | ||
| 1695 | } | ||
| 1696 | |||
| 1697 | temp = (udp_length<<8)|(udp_length>>8); | ||
| 1698 | fr_udp_pkt->udp_pkt.udp_length = temp; | ||
| 1699 | |||
| 1700 | /* swap UDP ports */ | ||
| 1701 | temp = fr_udp_pkt->udp_pkt.udp_src_port; | ||
| 1702 | fr_udp_pkt->udp_pkt.udp_src_port = | ||
| 1703 | fr_udp_pkt->udp_pkt.udp_dst_port; | ||
| 1704 | fr_udp_pkt->udp_pkt.udp_dst_port = temp; | ||
| 1705 | |||
| 1706 | |||
| 1707 | |||
| 1708 | /* add UDP pseudo header */ | ||
| 1709 | temp = 0x1100; | ||
| 1710 | *((unsigned short *) | ||
| 1711 | (fr_udp_pkt->data+mbox_len+even_bound)) = temp; | ||
| 1712 | temp = (udp_length<<8)|(udp_length>>8); | ||
| 1713 | *((unsigned short *) | ||
| 1714 | (fr_udp_pkt->data+mbox_len+even_bound+2)) = temp; | ||
| 1715 | |||
| 1716 | /* calculate UDP checksum */ | ||
| 1717 | fr_udp_pkt->udp_pkt.udp_checksum = 0; | ||
| 1718 | |||
| 1719 | fr_udp_pkt->udp_pkt.udp_checksum = | ||
| 1720 | calc_checksum(&data[UDP_OFFSET/*+sizeof(fr_encap_hdr_t)*/], | ||
| 1721 | udp_length+UDP_OFFSET); | ||
| 1722 | |||
| 1723 | /* fill in IP length */ | ||
| 1724 | ip_length = udp_length + sizeof(ip_pkt_t); | ||
| 1725 | temp = (ip_length<<8)|(ip_length>>8); | ||
| 1726 | fr_udp_pkt->ip_pkt.total_length = temp; | ||
| 1727 | |||
| 1728 | /* swap IP addresses */ | ||
| 1729 | ip_temp = fr_udp_pkt->ip_pkt.ip_src_address; | ||
| 1730 | fr_udp_pkt->ip_pkt.ip_src_address = | ||
| 1731 | fr_udp_pkt->ip_pkt.ip_dst_address; | ||
| 1732 | fr_udp_pkt->ip_pkt.ip_dst_address = ip_temp; | ||
| 1733 | |||
| 1734 | |||
| 1735 | /* fill in IP checksum */ | ||
| 1736 | fr_udp_pkt->ip_pkt.hdr_checksum = 0; | ||
| 1737 | fr_udp_pkt->ip_pkt.hdr_checksum = | ||
| 1738 | calc_checksum(&data[/*sizeof(fr_encap_hdr_t)*/0], | ||
| 1739 | sizeof(ip_pkt_t)); | ||
| 1740 | |||
| 1741 | return len; | ||
| 1742 | } /* reply_udp */ | ||
| 1743 | |||
| 1744 | unsigned short calc_checksum (char *data, int len) | ||
| 1745 | { | ||
| 1746 | unsigned short temp; | ||
| 1747 | unsigned long sum=0; | ||
| 1748 | int i; | ||
| 1749 | |||
| 1750 | for( i = 0; i <len; i+=2 ) { | ||
| 1751 | memcpy(&temp,&data[i],2); | ||
| 1752 | sum += (unsigned long)temp; | ||
| 1753 | } | ||
| 1754 | |||
| 1755 | while (sum >> 16 ) { | ||
| 1756 | sum = (sum & 0xffffUL) + (sum >> 16); | ||
| 1757 | } | ||
| 1758 | |||
| 1759 | temp = (unsigned short)sum; | ||
| 1760 | temp = ~temp; | ||
| 1761 | |||
| 1762 | if( temp == 0 ) | ||
| 1763 | temp = 0xffff; | ||
| 1764 | |||
| 1765 | return temp; | ||
| 1766 | } | ||
| 1767 | |||
| 1768 | /* | ||
| 1769 | If incoming is 0 (outgoing)- if the net numbers is ours make it 0 | ||
| 1770 | if incoming is 1 - if the net number is 0 make it ours | ||
| 1771 | |||
| 1772 | */ | ||
| 1773 | static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) | ||
| 1774 | { | ||
| 1775 | unsigned long pnetwork_number; | ||
| 1776 | |||
| 1777 | pnetwork_number = (unsigned long)((sendpacket[14] << 24) + | ||
| 1778 | (sendpacket[15] << 16) + (sendpacket[16] << 8) + | ||
| 1779 | sendpacket[17]); | ||
| 1780 | |||
| 1781 | if (!incoming) { | ||
| 1782 | /* If the destination network number is ours, make it 0 */ | ||
| 1783 | if( pnetwork_number == network_number) { | ||
| 1784 | sendpacket[14] = sendpacket[15] = sendpacket[16] = | ||
| 1785 | sendpacket[17] = 0x00; | ||
| 1786 | } | ||
| 1787 | } else { | ||
| 1788 | /* If the incoming network is 0, make it ours */ | ||
| 1789 | if( pnetwork_number == 0) { | ||
| 1790 | sendpacket[14] = (unsigned char)(network_number >> 24); | ||
| 1791 | sendpacket[15] = (unsigned char)((network_number & | ||
| 1792 | 0x00FF0000) >> 16); | ||
| 1793 | sendpacket[16] = (unsigned char)((network_number & | ||
| 1794 | 0x0000FF00) >> 8); | ||
| 1795 | sendpacket[17] = (unsigned char)(network_number & | ||
| 1796 | 0x000000FF); | ||
| 1797 | } | ||
| 1798 | } | ||
| 1799 | |||
| 1800 | |||
| 1801 | pnetwork_number = (unsigned long)((sendpacket[26] << 24) + | ||
| 1802 | (sendpacket[27] << 16) + (sendpacket[28] << 8) + | ||
| 1803 | sendpacket[29]); | ||
| 1804 | |||
| 1805 | if( !incoming ) { | ||
| 1806 | /* If the source network is ours, make it 0 */ | ||
| 1807 | if( pnetwork_number == network_number) { | ||
| 1808 | sendpacket[26] = sendpacket[27] = sendpacket[28] = | ||
| 1809 | sendpacket[29] = 0x00; | ||
| 1810 | } | ||
| 1811 | } else { | ||
| 1812 | /* If the source network is 0, make it ours */ | ||
| 1813 | if( pnetwork_number == 0 ) { | ||
| 1814 | sendpacket[26] = (unsigned char)(network_number >> 24); | ||
| 1815 | sendpacket[27] = (unsigned char)((network_number & | ||
| 1816 | 0x00FF0000) >> 16); | ||
| 1817 | sendpacket[28] = (unsigned char)((network_number & | ||
| 1818 | 0x0000FF00) >> 8); | ||
| 1819 | sendpacket[29] = (unsigned char)(network_number & | ||
| 1820 | 0x000000FF); | ||
| 1821 | } | ||
| 1822 | } | ||
| 1823 | } /* switch_net_numbers */ | ||
| 1824 | |||
| 1825 | /*============================================================================ | ||
| 1826 | * Get ethernet-style interface statistics. | ||
| 1827 | * Return a pointer to struct enet_statistics. | ||
| 1828 | */ | ||
| 1829 | static struct net_device_stats *if_stats(struct net_device *dev) | ||
| 1830 | { | ||
| 1831 | fr_channel_t* chan = dev->priv; | ||
| 1832 | |||
| 1833 | if(chan == NULL) | ||
| 1834 | return NULL; | ||
| 1835 | |||
| 1836 | return &chan->ifstats; | ||
| 1837 | } | ||
| 1838 | |||
| 1839 | /****** Interrupt Handlers **************************************************/ | ||
| 1840 | |||
| 1841 | /*============================================================================ | ||
| 1842 | * fr_isr: S508 frame relay interrupt service routine. | ||
| 1843 | * | ||
| 1844 | * Description: | ||
| 1845 | * Frame relay main interrupt service route. This | ||
| 1846 | * function check the interrupt type and takes | ||
| 1847 | * the appropriate action. | ||
| 1848 | */ | ||
| 1849 | static void fr_isr (sdla_t* card) | ||
| 1850 | { | ||
| 1851 | fr508_flags_t* flags = card->flags; | ||
| 1852 | char *ptr = &flags->iflag; | ||
| 1853 | int i,err; | ||
| 1854 | fr_mbox_t* mbox = card->mbox; | ||
| 1855 | |||
| 1856 | /* This flag prevents nesting of interrupts. See sdla_isr() routine | ||
| 1857 | * in sdlamain.c. */ | ||
| 1858 | card->in_isr = 1; | ||
| 1859 | |||
| 1860 | ++card->statistics.isr_entry; | ||
| 1861 | |||
| 1862 | |||
| 1863 | /* All peripheral (configuraiton, re-configuration) events | ||
| 1864 | * take presidence over the ISR. Thus, retrigger */ | ||
| 1865 | if (test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { | ||
| 1866 | ++card->statistics.isr_already_critical; | ||
| 1867 | goto fr_isr_exit; | ||
| 1868 | } | ||
| 1869 | |||
| 1870 | if(card->hw.type != SDLA_S514) { | ||
| 1871 | if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)) { | ||
| 1872 | printk(KERN_INFO "%s: Critical while in ISR: If Send Running!\n", | ||
| 1873 | card->devname); | ||
| 1874 | ++card->statistics.isr_already_critical; | ||
| 1875 | goto fr_isr_exit; | ||
| 1876 | } | ||
| 1877 | } | ||
| 1878 | |||
| 1879 | switch (flags->iflag) { | ||
| 1880 | |||
| 1881 | case FR_INTR_RXRDY: /* receive interrupt */ | ||
| 1882 | ++card->statistics.isr_rx; | ||
| 1883 | rx_intr(card); | ||
| 1884 | break; | ||
| 1885 | |||
| 1886 | |||
| 1887 | case FR_INTR_TXRDY: /* transmit interrupt */ | ||
| 1888 | ++ card->statistics.isr_tx; | ||
| 1889 | tx_intr(card); | ||
| 1890 | break; | ||
| 1891 | |||
| 1892 | case FR_INTR_READY: | ||
| 1893 | Intr_test_counter++; | ||
| 1894 | ++card->statistics.isr_intr_test; | ||
| 1895 | break; | ||
| 1896 | |||
| 1897 | case FR_INTR_DLC: /* Event interrupt occurred */ | ||
| 1898 | mbox->cmd.command = FR_READ_STATUS; | ||
| 1899 | mbox->cmd.length = 0; | ||
| 1900 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 1901 | if (err) | ||
| 1902 | fr_event(card, err, mbox); | ||
| 1903 | break; | ||
| 1904 | |||
| 1905 | case FR_INTR_TIMER: /* Timer interrupt */ | ||
| 1906 | timer_intr(card); | ||
| 1907 | break; | ||
| 1908 | |||
| 1909 | default: | ||
| 1910 | ++card->statistics.isr_spurious; | ||
| 1911 | spur_intr(card); | ||
| 1912 | printk(KERN_INFO "%s: Interrupt Type 0x%02X!\n", | ||
| 1913 | card->devname, flags->iflag); | ||
| 1914 | |||
| 1915 | printk(KERN_INFO "%s: ID Bytes = ",card->devname); | ||
| 1916 | for(i = 0; i < 8; i ++) | ||
| 1917 | printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); | ||
| 1918 | printk(KERN_INFO "\n"); | ||
| 1919 | |||
| 1920 | break; | ||
| 1921 | } | ||
| 1922 | |||
| 1923 | fr_isr_exit: | ||
| 1924 | |||
| 1925 | card->in_isr = 0; | ||
| 1926 | flags->iflag = 0; | ||
| 1927 | return; | ||
| 1928 | } | ||
| 1929 | |||
| 1930 | |||
| 1931 | |||
| 1932 | /*=========================================================== | ||
| 1933 | * rx_intr Receive interrupt handler. | ||
| 1934 | * | ||
| 1935 | * Description | ||
| 1936 | * Upon receiveing an interrupt: | ||
| 1937 | * 1. Check that the firmware is in sync with | ||
| 1938 | * the driver. | ||
| 1939 | * 2. Find an appropriate network interface | ||
| 1940 | * based on the received dlci number. | ||
| 1941 | * 3. Check that the netowrk interface exists | ||
| 1942 | * and that it's setup properly. | ||
| 1943 | * 4. Copy the data into an skb buffer. | ||
| 1944 | * 5. Check the packet type and take | ||
| 1945 | * appropriate acton: UPD, API, ARP or Data. | ||
| 1946 | */ | ||
| 1947 | |||
| 1948 | static void rx_intr (sdla_t* card) | ||
| 1949 | { | ||
| 1950 | fr_rx_buf_ctl_t* frbuf = card->rxmb; | ||
| 1951 | fr508_flags_t* flags = card->flags; | ||
| 1952 | fr_channel_t* chan; | ||
| 1953 | char *ptr = &flags->iflag; | ||
| 1954 | struct sk_buff* skb; | ||
| 1955 | struct net_device* dev; | ||
| 1956 | void* buf; | ||
| 1957 | unsigned dlci, len, offs, len_incl_hdr; | ||
| 1958 | int i, udp_type; | ||
| 1959 | |||
| 1960 | |||
| 1961 | /* Check that firmware buffers are in sync */ | ||
| 1962 | if (frbuf->flag != 0x01) { | ||
| 1963 | |||
| 1964 | printk(KERN_INFO | ||
| 1965 | "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", | ||
| 1966 | card->devname, (unsigned)frbuf, frbuf->flag); | ||
| 1967 | |||
| 1968 | printk(KERN_INFO "%s: ID Bytes = ",card->devname); | ||
| 1969 | for(i = 0; i < 8; i ++) | ||
| 1970 | printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); | ||
| 1971 | printk(KERN_INFO "\n"); | ||
| 1972 | |||
| 1973 | ++card->statistics.rx_intr_corrupt_rx_bfr; | ||
| 1974 | |||
| 1975 | /* Bug Fix: Mar 6 2000 | ||
| 1976 | * If we get a corrupted mailbox, it means that driver | ||
| 1977 | * is out of sync with the firmware. There is no recovery. | ||
| 1978 | * If we don't turn off all interrupts for this card | ||
| 1979 | * the machine will crash. | ||
| 1980 | */ | ||
| 1981 | printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); | ||
| 1982 | printk(KERN_INFO "Please contact Sangoma Technologies !\n"); | ||
| 1983 | fr_set_intr_mode(card, 0, 0, 0); | ||
| 1984 | return; | ||
| 1985 | } | ||
| 1986 | |||
| 1987 | len = frbuf->length; | ||
| 1988 | dlci = frbuf->dlci; | ||
| 1989 | offs = frbuf->offset; | ||
| 1990 | |||
| 1991 | /* Find the network interface for this packet */ | ||
| 1992 | dev = find_channel(card, dlci); | ||
| 1993 | |||
| 1994 | |||
| 1995 | /* Check that the network interface is active and | ||
| 1996 | * properly setup */ | ||
| 1997 | if (dev == NULL) { | ||
| 1998 | if( net_ratelimit()) { | ||
| 1999 | printk(KERN_INFO "%s: received data on unconfigured DLCI %d!\n", | ||
| 2000 | card->devname, dlci); | ||
| 2001 | } | ||
| 2002 | ++card->statistics.rx_intr_on_orphaned_DLCI; | ||
| 2003 | ++card->wandev.stats.rx_dropped; | ||
| 2004 | goto rx_done; | ||
| 2005 | } | ||
| 2006 | |||
| 2007 | if ((chan = dev->priv) == NULL){ | ||
| 2008 | if( net_ratelimit()) { | ||
| 2009 | printk(KERN_INFO "%s: received data on unconfigured DLCI %d!\n", | ||
| 2010 | card->devname, dlci); | ||
| 2011 | } | ||
| 2012 | ++card->statistics.rx_intr_on_orphaned_DLCI; | ||
| 2013 | ++card->wandev.stats.rx_dropped; | ||
| 2014 | goto rx_done; | ||
| 2015 | } | ||
| 2016 | |||
| 2017 | skb = dev_alloc_skb(len); | ||
| 2018 | |||
| 2019 | if (!netif_running(dev) || (skb == NULL)){ | ||
| 2020 | |||
| 2021 | ++chan->ifstats.rx_dropped; | ||
| 2022 | |||
| 2023 | if(skb == NULL) { | ||
| 2024 | if (net_ratelimit()) { | ||
| 2025 | printk(KERN_INFO | ||
| 2026 | "%s: no socket buffers available!\n", | ||
| 2027 | card->devname); | ||
| 2028 | } | ||
| 2029 | chan->drvstats_rx_intr.rx_intr_no_socket ++; | ||
| 2030 | } | ||
| 2031 | |||
| 2032 | if (!netif_running(dev)){ | ||
| 2033 | chan->drvstats_rx_intr. | ||
| 2034 | rx_intr_dev_not_started ++; | ||
| 2035 | if (skb){ | ||
| 2036 | dev_kfree_skb_any(skb); | ||
| 2037 | } | ||
| 2038 | } | ||
| 2039 | goto rx_done; | ||
| 2040 | } | ||
| 2041 | |||
| 2042 | /* Copy data from the board into the socket buffer */ | ||
| 2043 | if ((offs + len) > card->u.f.rx_top + 1) { | ||
| 2044 | unsigned tmp = card->u.f.rx_top - offs + 1; | ||
| 2045 | |||
| 2046 | buf = skb_put(skb, tmp); | ||
| 2047 | sdla_peek(&card->hw, offs, buf, tmp); | ||
| 2048 | offs = card->u.f.rx_base; | ||
| 2049 | len -= tmp; | ||
| 2050 | } | ||
| 2051 | |||
| 2052 | buf = skb_put(skb, len); | ||
| 2053 | sdla_peek(&card->hw, offs, buf, len); | ||
| 2054 | |||
| 2055 | |||
| 2056 | /* We got the packet from the bard. | ||
| 2057 | * Check the packet type and take appropriate action */ | ||
| 2058 | |||
| 2059 | udp_type = udp_pkt_type( skb, card ); | ||
| 2060 | |||
| 2061 | if(udp_type != UDP_INVALID_TYPE) { | ||
| 2062 | |||
| 2063 | /* UDP Debug packet received, store the | ||
| 2064 | * packet and handle it in timer interrupt */ | ||
| 2065 | |||
| 2066 | skb_pull(skb, 1); | ||
| 2067 | if (wanrouter_type_trans(skb, dev)){ | ||
| 2068 | if(store_udp_mgmt_pkt(udp_type,UDP_PKT_FRM_NETWORK,card,skb,dlci)){ | ||
| 2069 | |||
| 2070 | flags->imask |= FR_INTR_TIMER; | ||
| 2071 | |||
| 2072 | if (udp_type == UDP_FPIPE_TYPE){ | ||
| 2073 | ++chan->drvstats_rx_intr.rx_intr_PIPE_request; | ||
| 2074 | } | ||
| 2075 | } | ||
| 2076 | } | ||
| 2077 | |||
| 2078 | }else if (chan->common.usedby == API) { | ||
| 2079 | |||
| 2080 | /* We are in API mode. | ||
| 2081 | * Add an API header to the RAW packet | ||
| 2082 | * and queue it into a circular buffer. | ||
| 2083 | * Then kick the fr_bh() bottom half handler */ | ||
| 2084 | |||
| 2085 | api_rx_hdr_t* api_rx_hdr; | ||
| 2086 | chan->drvstats_rx_intr.rx_intr_bfr_passed_to_stack ++; | ||
| 2087 | chan->ifstats.rx_packets ++; | ||
| 2088 | card->wandev.stats.rx_packets ++; | ||
| 2089 | |||
| 2090 | chan->ifstats.rx_bytes += skb->len; | ||
| 2091 | card->wandev.stats.rx_bytes += skb->len; | ||
| 2092 | |||
| 2093 | skb_push(skb, sizeof(api_rx_hdr_t)); | ||
| 2094 | api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00]; | ||
| 2095 | api_rx_hdr->attr = frbuf->attr; | ||
| 2096 | api_rx_hdr->time_stamp = frbuf->tmstamp; | ||
| 2097 | |||
| 2098 | skb->protocol = htons(ETH_P_IP); | ||
| 2099 | skb->mac.raw = skb->data; | ||
| 2100 | skb->dev = dev; | ||
| 2101 | skb->pkt_type = WAN_PACKET_DATA; | ||
| 2102 | |||
| 2103 | bh_enqueue(dev, skb); | ||
| 2104 | |||
| 2105 | trigger_fr_bh(chan); | ||
| 2106 | |||
| 2107 | }else if (handle_IPXWAN(skb->data,chan->name,chan->enable_IPX, chan->network_number)){ | ||
| 2108 | |||
| 2109 | //FIXME: Frame Relay IPX is not supported, Yet ! | ||
| 2110 | //if (chan->enable_IPX) { | ||
| 2111 | // fr_send(card, dlci, 0, skb->len,skb->data); | ||
| 2112 | //} | ||
| 2113 | dev_kfree_skb_any(skb); | ||
| 2114 | |||
| 2115 | } else if (is_arp(skb->data)) { | ||
| 2116 | |||
| 2117 | /* ARP support enabled Mar 16 2000 | ||
| 2118 | * Process incoming ARP reply/request, setup | ||
| 2119 | * dynamic routes. */ | ||
| 2120 | |||
| 2121 | if (process_ARP((arphdr_1490_t *)skb->data, card, dev)) { | ||
| 2122 | if (net_ratelimit()){ | ||
| 2123 | printk (KERN_INFO | ||
| 2124 | "%s: Error processing ARP Packet.\n", | ||
| 2125 | card->devname); | ||
| 2126 | } | ||
| 2127 | } | ||
| 2128 | dev_kfree_skb_any(skb); | ||
| 2129 | |||
| 2130 | } else if (skb->data[0] != 0x03) { | ||
| 2131 | |||
| 2132 | if (net_ratelimit()) { | ||
| 2133 | printk(KERN_INFO "%s: Non IETF packet discarded.\n", | ||
| 2134 | card->devname); | ||
| 2135 | } | ||
| 2136 | dev_kfree_skb_any(skb); | ||
| 2137 | |||
| 2138 | } else { | ||
| 2139 | |||
| 2140 | len_incl_hdr = skb->len; | ||
| 2141 | /* Decapsulate packet and pass it up the | ||
| 2142 | protocol stack */ | ||
| 2143 | skb->dev = dev; | ||
| 2144 | |||
| 2145 | if (chan->common.usedby == BRIDGE || chan->common.usedby == BRIDGE_NODE){ | ||
| 2146 | |||
| 2147 | /* Make sure it's an Ethernet frame, otherwise drop it */ | ||
| 2148 | if (!memcmp(skb->data, "\x03\x00\x80\x00\x80\xC2\x00\x07", 8)) { | ||
| 2149 | skb_pull(skb, 8); | ||
| 2150 | skb->protocol=eth_type_trans(skb,dev); | ||
| 2151 | }else{ | ||
| 2152 | ++chan->drvstats_rx_intr.rx_intr_bfr_not_passed_to_stack; | ||
| 2153 | ++chan->ifstats.rx_errors; | ||
| 2154 | ++card->wandev.stats.rx_errors; | ||
| 2155 | goto rx_done; | ||
| 2156 | } | ||
| 2157 | }else{ | ||
| 2158 | |||
| 2159 | /* remove hardware header */ | ||
| 2160 | buf = skb_pull(skb, 1); | ||
| 2161 | |||
| 2162 | if (!wanrouter_type_trans(skb, dev)) { | ||
| 2163 | |||
| 2164 | /* can't decapsulate packet */ | ||
| 2165 | dev_kfree_skb_any(skb); | ||
| 2166 | |||
| 2167 | ++chan->drvstats_rx_intr.rx_intr_bfr_not_passed_to_stack; | ||
| 2168 | ++chan->ifstats.rx_errors; | ||
| 2169 | ++card->wandev.stats.rx_errors; | ||
| 2170 | goto rx_done; | ||
| 2171 | } | ||
| 2172 | skb->mac.raw = skb->data; | ||
| 2173 | } | ||
| 2174 | |||
| 2175 | |||
| 2176 | /* Send a packet up the IP stack */ | ||
| 2177 | skb->dev->last_rx = jiffies; | ||
| 2178 | netif_rx(skb); | ||
| 2179 | ++chan->drvstats_rx_intr.rx_intr_bfr_passed_to_stack; | ||
| 2180 | ++chan->ifstats.rx_packets; | ||
| 2181 | ++card->wandev.stats.rx_packets; | ||
| 2182 | |||
| 2183 | chan->ifstats.rx_bytes += len_incl_hdr; | ||
| 2184 | card->wandev.stats.rx_bytes += len_incl_hdr; | ||
| 2185 | } | ||
| 2186 | |||
| 2187 | rx_done: | ||
| 2188 | |||
| 2189 | /* Release buffer element and calculate a pointer to the next one */ | ||
| 2190 | frbuf->flag = 0; | ||
| 2191 | card->rxmb = ++frbuf; | ||
| 2192 | if ((void*)frbuf > card->u.f.rxmb_last) | ||
| 2193 | card->rxmb = card->u.f.rxmb_base; | ||
| 2194 | |||
| 2195 | } | ||
| 2196 | |||
| 2197 | /*================================================================== | ||
| 2198 | * tx_intr: Transmit interrupt handler. | ||
| 2199 | * | ||
| 2200 | * Rationale: | ||
| 2201 | * If the board is busy transmitting, if_send() will | ||
| 2202 | * buffers a single packet and turn on | ||
| 2203 | * the tx interrupt. Tx interrupt will be called | ||
| 2204 | * by the board, once the firmware can send more | ||
| 2205 | * data. Thus, no polling is required. | ||
| 2206 | * | ||
| 2207 | * Description: | ||
| 2208 | * Tx interrupt is called for each | ||
| 2209 | * configured dlci channel. Thus: | ||
| 2210 | * 1. Obtain the netowrk interface based on the | ||
| 2211 | * dlci number. | ||
| 2212 | * 2. Check that network interface is up and | ||
| 2213 | * properly setup. | ||
| 2214 | * 3. Check for a buffered packet. | ||
| 2215 | * 4. Transmit the packet. | ||
| 2216 | * 5. If we are in WANPIPE mode, mark the | ||
| 2217 | * NET_BH handler. | ||
| 2218 | * 6. If we are in API mode, kick | ||
| 2219 | * the AF_WANPIPE socket for more data. | ||
| 2220 | * | ||
| 2221 | */ | ||
| 2222 | static void tx_intr(sdla_t *card) | ||
| 2223 | { | ||
| 2224 | fr508_flags_t* flags = card->flags; | ||
| 2225 | fr_tx_buf_ctl_t* bctl; | ||
| 2226 | struct net_device* dev; | ||
| 2227 | fr_channel_t* chan; | ||
| 2228 | |||
| 2229 | if(card->hw.type == SDLA_S514){ | ||
| 2230 | bctl = (void*)(flags->tse_offs + card->hw.dpmbase); | ||
| 2231 | }else{ | ||
| 2232 | bctl = (void*)(flags->tse_offs - FR_MB_VECTOR + | ||
| 2233 | card->hw.dpmbase); | ||
| 2234 | } | ||
| 2235 | |||
| 2236 | /* Find the structure and make it unbusy */ | ||
| 2237 | dev = find_channel(card, flags->dlci); | ||
| 2238 | if (dev == NULL){ | ||
| 2239 | printk(KERN_INFO "NO DEV IN TX Interrupt\n"); | ||
| 2240 | goto end_of_tx_intr; | ||
| 2241 | } | ||
| 2242 | |||
| 2243 | if ((chan = dev->priv) == NULL){ | ||
| 2244 | printk(KERN_INFO "NO CHAN IN TX Interrupt\n"); | ||
| 2245 | goto end_of_tx_intr; | ||
| 2246 | } | ||
| 2247 | |||
| 2248 | if(!chan->transmit_length || !chan->delay_skb) { | ||
| 2249 | printk(KERN_INFO "%s: tx int error - transmit length zero\n", | ||
| 2250 | card->wandev.name); | ||
| 2251 | goto end_of_tx_intr; | ||
| 2252 | } | ||
| 2253 | |||
| 2254 | /* If the 'if_send()' procedure is currently checking the 'tbusy' | ||
| 2255 | status, then we cannot transmit. Instead, we configure the microcode | ||
| 2256 | so as to re-issue this transmit interrupt at a later stage. | ||
| 2257 | */ | ||
| 2258 | if (test_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical)) { | ||
| 2259 | |||
| 2260 | fr_dlci_interface_t* dlci_interface = chan->dlci_int_interface; | ||
| 2261 | bctl->flag = 0xA0; | ||
| 2262 | dlci_interface->gen_interrupt |= FR_INTR_TXRDY; | ||
| 2263 | return; | ||
| 2264 | |||
| 2265 | }else{ | ||
| 2266 | bctl->dlci = flags->dlci; | ||
| 2267 | bctl->length = chan->transmit_length+chan->fr_header_len; | ||
| 2268 | sdla_poke(&card->hw, | ||
| 2269 | fr_send_hdr(card,bctl->dlci,bctl->offset), | ||
| 2270 | chan->delay_skb->data, | ||
| 2271 | chan->delay_skb->len); | ||
| 2272 | bctl->flag = 0xC0; | ||
| 2273 | |||
| 2274 | ++chan->ifstats.tx_packets; | ||
| 2275 | ++card->wandev.stats.tx_packets; | ||
| 2276 | chan->ifstats.tx_bytes += chan->transmit_length; | ||
| 2277 | card->wandev.stats.tx_bytes += chan->transmit_length; | ||
| 2278 | |||
| 2279 | /* We must free an sk buffer, which we used | ||
| 2280 | * for delayed transmission; Otherwise, the sock | ||
| 2281 | * will run out of memory */ | ||
| 2282 | dev_kfree_skb_any(chan->delay_skb); | ||
| 2283 | |||
| 2284 | chan->delay_skb = NULL; | ||
| 2285 | chan->transmit_length = 0; | ||
| 2286 | |||
| 2287 | dev->trans_start = jiffies; | ||
| 2288 | |||
| 2289 | if (netif_queue_stopped(dev)){ | ||
| 2290 | /* If using API, than wakeup socket BH handler */ | ||
| 2291 | if (chan->common.usedby == API){ | ||
| 2292 | netif_start_queue(dev); | ||
| 2293 | wakeup_sk_bh(dev); | ||
| 2294 | }else{ | ||
| 2295 | netif_wake_queue(dev); | ||
| 2296 | } | ||
| 2297 | } | ||
| 2298 | } | ||
| 2299 | |||
| 2300 | end_of_tx_intr: | ||
| 2301 | |||
| 2302 | /* if any other interfaces have transmit interrupts pending, | ||
| 2303 | * do not disable the global transmit interrupt */ | ||
| 2304 | if(!(-- card->u.f.tx_interrupts_pending)) | ||
| 2305 | flags->imask &= ~FR_INTR_TXRDY; | ||
| 2306 | |||
| 2307 | |||
| 2308 | } | ||
| 2309 | |||
| 2310 | |||
| 2311 | /*============================================================================ | ||
| 2312 | * timer_intr: Timer interrupt handler. | ||
| 2313 | * | ||
| 2314 | * Rationale: | ||
| 2315 | * All commans must be executed within the timer | ||
| 2316 | * interrupt since no two commands should execute | ||
| 2317 | * at the same time. | ||
| 2318 | * | ||
| 2319 | * Description: | ||
| 2320 | * The timer interrupt is used to: | ||
| 2321 | * 1. Processing udp calls from 'fpipemon'. | ||
| 2322 | * 2. Processing update calls from /proc file system | ||
| 2323 | * 3. Reading board-level statistics for | ||
| 2324 | * updating the proc file system. | ||
| 2325 | * 4. Sending inverse ARP request packets. | ||
| 2326 | * 5. Configure a dlci/channel. | ||
| 2327 | * 6. Unconfigure a dlci/channel. (Node only) | ||
| 2328 | */ | ||
| 2329 | |||
| 2330 | static void timer_intr(sdla_t *card) | ||
| 2331 | { | ||
| 2332 | fr508_flags_t* flags = card->flags; | ||
| 2333 | |||
| 2334 | /* UDP Debuging: fpipemon call */ | ||
| 2335 | if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UDP) { | ||
| 2336 | if(card->u.f.udp_type == UDP_FPIPE_TYPE) { | ||
| 2337 | if(process_udp_mgmt_pkt(card)) { | ||
| 2338 | card->u.f.timer_int_enabled &= | ||
| 2339 | ~TMR_INT_ENABLED_UDP; | ||
| 2340 | } | ||
| 2341 | } | ||
| 2342 | } | ||
| 2343 | |||
| 2344 | /* /proc update call : triggered from update() */ | ||
| 2345 | if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE) { | ||
| 2346 | fr_get_err_stats(card); | ||
| 2347 | fr_get_stats(card); | ||
| 2348 | card->u.f.update_comms_stats = 0; | ||
| 2349 | card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; | ||
| 2350 | } | ||
| 2351 | |||
| 2352 | /* Update the channel state call. This is call is | ||
| 2353 | * triggered by if_send() function */ | ||
| 2354 | if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE_STATE){ | ||
| 2355 | struct net_device *dev; | ||
| 2356 | if (card->wandev.state == WAN_CONNECTED){ | ||
| 2357 | for (dev = card->wandev.dev; dev; | ||
| 2358 | dev = *((struct net_device **)dev->priv)){ | ||
| 2359 | fr_channel_t *chan = dev->priv; | ||
| 2360 | if (chan->common.state != WAN_CONNECTED){ | ||
| 2361 | update_chan_state(dev); | ||
| 2362 | } | ||
| 2363 | } | ||
| 2364 | } | ||
| 2365 | card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE_STATE; | ||
| 2366 | } | ||
| 2367 | |||
| 2368 | /* configure a dlci/channel */ | ||
| 2369 | if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_CONFIG){ | ||
| 2370 | config_fr(card); | ||
| 2371 | card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG; | ||
| 2372 | } | ||
| 2373 | |||
| 2374 | /* unconfigure a dlci/channel */ | ||
| 2375 | if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UNCONFIG){ | ||
| 2376 | unconfig_fr(card); | ||
| 2377 | card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UNCONFIG; | ||
| 2378 | } | ||
| 2379 | |||
| 2380 | |||
| 2381 | /* Transmit ARP packets */ | ||
| 2382 | if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_ARP){ | ||
| 2383 | int i=0; | ||
| 2384 | struct net_device *dev; | ||
| 2385 | |||
| 2386 | if (card->u.f.arp_dev == NULL) | ||
| 2387 | card->u.f.arp_dev = card->wandev.dev; | ||
| 2388 | |||
| 2389 | dev = card->u.f.arp_dev; | ||
| 2390 | |||
| 2391 | for (;;){ | ||
| 2392 | |||
| 2393 | fr_channel_t *chan = dev->priv; | ||
| 2394 | |||
| 2395 | /* If the interface is brought down cancel sending In-ARPs */ | ||
| 2396 | if (!(dev->flags&IFF_UP)){ | ||
| 2397 | clear_bit(0,&chan->inarp_ready); | ||
| 2398 | } | ||
| 2399 | |||
| 2400 | if (test_bit(0,&chan->inarp_ready)){ | ||
| 2401 | |||
| 2402 | if (check_tx_status(card,dev)){ | ||
| 2403 | set_bit(ARP_CRIT,&card->wandev.critical); | ||
| 2404 | break; | ||
| 2405 | } | ||
| 2406 | |||
| 2407 | if (!send_inarp_request(card,dev)){ | ||
| 2408 | trigger_fr_arp(dev); | ||
| 2409 | chan->inarp_tick = jiffies; | ||
| 2410 | } | ||
| 2411 | |||
| 2412 | clear_bit(0,&chan->inarp_ready); | ||
| 2413 | dev = move_dev_to_next(card,dev); | ||
| 2414 | break; | ||
| 2415 | } | ||
| 2416 | dev = move_dev_to_next(card,dev); | ||
| 2417 | |||
| 2418 | if (++i == card->wandev.new_if_cnt){ | ||
| 2419 | card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_ARP; | ||
| 2420 | break; | ||
| 2421 | } | ||
| 2422 | } | ||
| 2423 | card->u.f.arp_dev = dev; | ||
| 2424 | } | ||
| 2425 | |||
| 2426 | if(!card->u.f.timer_int_enabled) | ||
| 2427 | flags->imask &= ~FR_INTR_TIMER; | ||
| 2428 | } | ||
| 2429 | |||
| 2430 | |||
| 2431 | /*============================================================================ | ||
| 2432 | * spur_intr: Spurious interrupt handler. | ||
| 2433 | * | ||
| 2434 | * Description: | ||
| 2435 | * We don't know this interrupt. | ||
| 2436 | * Print a warning. | ||
| 2437 | */ | ||
| 2438 | |||
| 2439 | static void spur_intr (sdla_t* card) | ||
| 2440 | { | ||
| 2441 | if (net_ratelimit()){ | ||
| 2442 | printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); | ||
| 2443 | } | ||
| 2444 | } | ||
| 2445 | |||
| 2446 | |||
| 2447 | //FIXME: Fix the IPX in next version | ||
| 2448 | /*=========================================================================== | ||
| 2449 | * Return 0 for non-IPXWAN packet | ||
| 2450 | * 1 for IPXWAN packet or IPX is not enabled! | ||
| 2451 | * FIXME: Use a IPX structure here not offsets | ||
| 2452 | */ | ||
| 2453 | static int handle_IPXWAN(unsigned char *sendpacket, | ||
| 2454 | char *devname, unsigned char enable_IPX, | ||
| 2455 | unsigned long network_number) | ||
| 2456 | { | ||
| 2457 | int i; | ||
| 2458 | |||
| 2459 | if( sendpacket[1] == 0x00 && sendpacket[2] == 0x80 && | ||
| 2460 | sendpacket[6] == 0x81 && sendpacket[7] == 0x37) { | ||
| 2461 | |||
| 2462 | /* It's an IPX packet */ | ||
| 2463 | if (!enable_IPX){ | ||
| 2464 | /* Return 1 so we don't pass it up the stack. */ | ||
| 2465 | //FIXME: Take this out when IPX is fixed | ||
| 2466 | if (net_ratelimit()){ | ||
| 2467 | printk (KERN_INFO | ||
| 2468 | "%s: WARNING: Unsupported IPX packet received and dropped\n", | ||
| 2469 | devname); | ||
| 2470 | } | ||
| 2471 | return 1; | ||
| 2472 | } | ||
| 2473 | } else { | ||
| 2474 | /* It's not IPX so return and pass it up the stack. */ | ||
| 2475 | return 0; | ||
| 2476 | } | ||
| 2477 | |||
| 2478 | if( sendpacket[24] == 0x90 && sendpacket[25] == 0x04){ | ||
| 2479 | /* It's IPXWAN */ | ||
| 2480 | |||
| 2481 | if( sendpacket[10] == 0x02 && sendpacket[42] == 0x00){ | ||
| 2482 | |||
| 2483 | /* It's a timer request packet */ | ||
| 2484 | printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n", | ||
| 2485 | devname); | ||
| 2486 | |||
| 2487 | /* Go through the routing options and answer no to every | ||
| 2488 | * option except Unnumbered RIP/SAP | ||
| 2489 | */ | ||
| 2490 | for(i = 49; sendpacket[i] == 0x00; i += 5){ | ||
| 2491 | /* 0x02 is the option for Unnumbered RIP/SAP */ | ||
| 2492 | if( sendpacket[i + 4] != 0x02){ | ||
| 2493 | sendpacket[i + 1] = 0; | ||
| 2494 | } | ||
| 2495 | } | ||
| 2496 | |||
| 2497 | /* Skip over the extended Node ID option */ | ||
| 2498 | if( sendpacket[i] == 0x04 ){ | ||
| 2499 | i += 8; | ||
| 2500 | } | ||
| 2501 | |||
| 2502 | /* We also want to turn off all header compression opt. | ||
| 2503 | */ | ||
| 2504 | for(; sendpacket[i] == 0x80 ;){ | ||
| 2505 | sendpacket[i + 1] = 0; | ||
| 2506 | i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; | ||
| 2507 | } | ||
| 2508 | |||
| 2509 | /* Set the packet type to timer response */ | ||
| 2510 | sendpacket[42] = 0x01; | ||
| 2511 | |||
| 2512 | printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n", | ||
| 2513 | devname); | ||
| 2514 | |||
| 2515 | } else if( sendpacket[42] == 0x02 ){ | ||
| 2516 | |||
| 2517 | /* This is an information request packet */ | ||
| 2518 | printk(KERN_INFO | ||
| 2519 | "%s: Received IPXWAN Information Request packet\n", | ||
| 2520 | devname); | ||
| 2521 | |||
| 2522 | /* Set the packet type to information response */ | ||
| 2523 | sendpacket[42] = 0x03; | ||
| 2524 | |||
| 2525 | /* Set the router name */ | ||
| 2526 | sendpacket[59] = 'F'; | ||
| 2527 | sendpacket[60] = 'P'; | ||
| 2528 | sendpacket[61] = 'I'; | ||
| 2529 | sendpacket[62] = 'P'; | ||
| 2530 | sendpacket[63] = 'E'; | ||
| 2531 | sendpacket[64] = '-'; | ||
| 2532 | sendpacket[65] = CVHexToAscii(network_number >> 28); | ||
| 2533 | sendpacket[66] = CVHexToAscii((network_number & 0x0F000000)>> 24); | ||
| 2534 | sendpacket[67] = CVHexToAscii((network_number & 0x00F00000)>> 20); | ||
| 2535 | sendpacket[68] = CVHexToAscii((network_number & 0x000F0000)>> 16); | ||
| 2536 | sendpacket[69] = CVHexToAscii((network_number & 0x0000F000)>> 12); | ||
| 2537 | sendpacket[70] = CVHexToAscii((network_number & 0x00000F00)>> 8); | ||
| 2538 | sendpacket[71] = CVHexToAscii((network_number & 0x000000F0)>> 4); | ||
| 2539 | sendpacket[72] = CVHexToAscii(network_number & 0x0000000F); | ||
| 2540 | for(i = 73; i < 107; i+= 1) | ||
| 2541 | { | ||
| 2542 | sendpacket[i] = 0; | ||
| 2543 | } | ||
| 2544 | |||
| 2545 | printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n", | ||
| 2546 | devname); | ||
| 2547 | } else { | ||
| 2548 | |||
| 2549 | printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); | ||
| 2550 | return 0; | ||
| 2551 | } | ||
| 2552 | |||
| 2553 | /* Set the WNodeID to our network address */ | ||
| 2554 | sendpacket[43] = (unsigned char)(network_number >> 24); | ||
| 2555 | sendpacket[44] = (unsigned char)((network_number & 0x00FF0000) >> 16); | ||
| 2556 | sendpacket[45] = (unsigned char)((network_number & 0x0000FF00) >> 8); | ||
| 2557 | sendpacket[46] = (unsigned char)(network_number & 0x000000FF); | ||
| 2558 | |||
| 2559 | return 1; | ||
| 2560 | } | ||
| 2561 | |||
| 2562 | /* If we get here, it's an IPX-data packet so it'll get passed up the | ||
| 2563 | * stack. | ||
| 2564 | * switch the network numbers | ||
| 2565 | */ | ||
| 2566 | switch_net_numbers(sendpacket, network_number ,1); | ||
| 2567 | return 0; | ||
| 2568 | } | ||
| 2569 | /*============================================================================ | ||
| 2570 | * process_route | ||
| 2571 | * | ||
| 2572 | * Rationale: | ||
| 2573 | * If the interface goes down, or we receive an ARP request, | ||
| 2574 | * we have to change the network interface ip addresses. | ||
| 2575 | * This cannot be done within the interrupt. | ||
| 2576 | * | ||
| 2577 | * Description: | ||
| 2578 | * | ||
| 2579 | * This routine is called as a polling routine to dynamically | ||
| 2580 | * add/delete routes negotiated by inverse ARP. It is in this | ||
| 2581 | * "task" because we don't want routes to be added while in | ||
| 2582 | * interrupt context. | ||
| 2583 | * | ||
| 2584 | * Usage: | ||
| 2585 | * This function is called by fr_poll() polling funtion. | ||
| 2586 | */ | ||
| 2587 | |||
| 2588 | static void process_route(struct net_device *dev) | ||
| 2589 | { | ||
| 2590 | fr_channel_t *chan = dev->priv; | ||
| 2591 | sdla_t *card = chan->card; | ||
| 2592 | |||
| 2593 | struct ifreq if_info; | ||
| 2594 | struct sockaddr_in *if_data; | ||
| 2595 | mm_segment_t fs = get_fs(); | ||
| 2596 | u32 ip_tmp; | ||
| 2597 | int err; | ||
| 2598 | |||
| 2599 | |||
| 2600 | switch(chan->route_flag){ | ||
| 2601 | |||
| 2602 | case ADD_ROUTE: | ||
| 2603 | |||
| 2604 | /* Set remote addresses */ | ||
| 2605 | memset(&if_info, 0, sizeof(if_info)); | ||
| 2606 | strcpy(if_info.ifr_name, dev->name); | ||
| 2607 | |||
| 2608 | set_fs(get_ds()); /* get user space block */ | ||
| 2609 | |||
| 2610 | if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; | ||
| 2611 | if_data->sin_addr.s_addr = chan->ip_remote; | ||
| 2612 | if_data->sin_family = AF_INET; | ||
| 2613 | err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); | ||
| 2614 | |||
| 2615 | set_fs(fs); /* restore old block */ | ||
| 2616 | |||
| 2617 | if (err) { | ||
| 2618 | printk(KERN_INFO | ||
| 2619 | "%s: Route Add failed. Error: %d\n", | ||
| 2620 | card->devname,err); | ||
| 2621 | printk(KERN_INFO "%s: Address: %u.%u.%u.%u\n", | ||
| 2622 | chan->name, NIPQUAD(chan->ip_remote)); | ||
| 2623 | |||
| 2624 | }else { | ||
| 2625 | printk(KERN_INFO "%s: Route Added Successfully: %u.%u.%u.%u\n", | ||
| 2626 | card->devname,NIPQUAD(chan->ip_remote)); | ||
| 2627 | chan->route_flag = ROUTE_ADDED; | ||
| 2628 | } | ||
| 2629 | break; | ||
| 2630 | |||
| 2631 | case REMOVE_ROUTE: | ||
| 2632 | |||
| 2633 | /* Set remote addresses */ | ||
| 2634 | memset(&if_info, 0, sizeof(if_info)); | ||
| 2635 | strcpy(if_info.ifr_name, dev->name); | ||
| 2636 | |||
| 2637 | ip_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP); | ||
| 2638 | |||
| 2639 | set_fs(get_ds()); /* get user space block */ | ||
| 2640 | |||
| 2641 | if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; | ||
| 2642 | if_data->sin_addr.s_addr = 0; | ||
| 2643 | if_data->sin_family = AF_INET; | ||
| 2644 | err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); | ||
| 2645 | |||
| 2646 | set_fs(fs); | ||
| 2647 | |||
| 2648 | if (err) { | ||
| 2649 | printk(KERN_INFO | ||
| 2650 | "%s: Deleting of route failed. Error: %d\n", | ||
| 2651 | card->devname,err); | ||
| 2652 | printk(KERN_INFO "%s: Address: %u.%u.%u.%u\n", | ||
| 2653 | dev->name,NIPQUAD(chan->ip_remote) ); | ||
| 2654 | |||
| 2655 | } else { | ||
| 2656 | printk(KERN_INFO "%s: Route Removed Sucessfuly: %u.%u.%u.%u\n", | ||
| 2657 | card->devname,NIPQUAD(ip_tmp)); | ||
| 2658 | chan->route_flag = NO_ROUTE; | ||
| 2659 | } | ||
| 2660 | break; | ||
| 2661 | |||
| 2662 | } /* Case Statement */ | ||
| 2663 | |||
| 2664 | } | ||
| 2665 | |||
| 2666 | |||
| 2667 | |||
| 2668 | /****** Frame Relay Firmware-Specific Functions *****************************/ | ||
| 2669 | |||
| 2670 | /*============================================================================ | ||
| 2671 | * Read firmware code version. | ||
| 2672 | * o fill string str with firmware version info. | ||
| 2673 | */ | ||
| 2674 | static int fr_read_version (sdla_t* card, char* str) | ||
| 2675 | { | ||
| 2676 | fr_mbox_t* mbox = card->mbox; | ||
| 2677 | int retry = MAX_CMD_RETRY; | ||
| 2678 | int err; | ||
| 2679 | |||
| 2680 | do | ||
| 2681 | { | ||
| 2682 | mbox->cmd.command = FR_READ_CODE_VERSION; | ||
| 2683 | mbox->cmd.length = 0; | ||
| 2684 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2685 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
| 2686 | |||
| 2687 | if (!err && str) { | ||
| 2688 | int len = mbox->cmd.length; | ||
| 2689 | memcpy(str, mbox->data, len); | ||
| 2690 | str[len] = '\0'; | ||
| 2691 | } | ||
| 2692 | return err; | ||
| 2693 | } | ||
| 2694 | |||
| 2695 | /*============================================================================ | ||
| 2696 | * Set global configuration. | ||
| 2697 | */ | ||
| 2698 | static int fr_configure (sdla_t* card, fr_conf_t *conf) | ||
| 2699 | { | ||
| 2700 | fr_mbox_t* mbox = card->mbox; | ||
| 2701 | int retry = MAX_CMD_RETRY; | ||
| 2702 | int dlci_num = card->u.f.dlci_num; | ||
| 2703 | int err, i; | ||
| 2704 | |||
| 2705 | do | ||
| 2706 | { | ||
| 2707 | memcpy(mbox->data, conf, sizeof(fr_conf_t)); | ||
| 2708 | |||
| 2709 | if (dlci_num) for (i = 0; i < dlci_num; ++i) | ||
| 2710 | ((fr_conf_t*)mbox->data)->dlci[i] = | ||
| 2711 | card->u.f.node_dlci[i]; | ||
| 2712 | |||
| 2713 | mbox->cmd.command = FR_SET_CONFIG; | ||
| 2714 | mbox->cmd.length = | ||
| 2715 | sizeof(fr_conf_t) + dlci_num * sizeof(short); | ||
| 2716 | |||
| 2717 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2718 | |||
| 2719 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
| 2720 | |||
| 2721 | /*NC Oct 12 2000 */ | ||
| 2722 | if (err != CMD_OK){ | ||
| 2723 | printk(KERN_ERR "%s: Frame Relay Configuration Failed: rc=0x%x\n", | ||
| 2724 | card->devname,err); | ||
| 2725 | } | ||
| 2726 | |||
| 2727 | return err; | ||
| 2728 | } | ||
| 2729 | |||
| 2730 | /*============================================================================ | ||
| 2731 | * Set DLCI configuration. | ||
| 2732 | */ | ||
| 2733 | static int fr_dlci_configure (sdla_t* card, fr_dlc_conf_t *conf, unsigned dlci) | ||
| 2734 | { | ||
| 2735 | fr_mbox_t* mbox = card->mbox; | ||
| 2736 | int retry = MAX_CMD_RETRY; | ||
| 2737 | int err; | ||
| 2738 | |||
| 2739 | do | ||
| 2740 | { | ||
| 2741 | memcpy(mbox->data, conf, sizeof(fr_dlc_conf_t)); | ||
| 2742 | mbox->cmd.dlci = (unsigned short) dlci; | ||
| 2743 | mbox->cmd.command = FR_SET_CONFIG; | ||
| 2744 | mbox->cmd.length = sizeof(fr_dlc_conf_t); | ||
| 2745 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2746 | } while (err && retry--); | ||
| 2747 | |||
| 2748 | return err; | ||
| 2749 | } | ||
| 2750 | /*============================================================================ | ||
| 2751 | * Set interrupt mode. | ||
| 2752 | */ | ||
| 2753 | static int fr_set_intr_mode (sdla_t* card, unsigned mode, unsigned mtu, | ||
| 2754 | unsigned short timeout) | ||
| 2755 | { | ||
| 2756 | fr_mbox_t* mbox = card->mbox; | ||
| 2757 | fr508_intr_ctl_t* ictl = (void*)mbox->data; | ||
| 2758 | int retry = MAX_CMD_RETRY; | ||
| 2759 | int err; | ||
| 2760 | |||
| 2761 | do | ||
| 2762 | { | ||
| 2763 | memset(ictl, 0, sizeof(fr508_intr_ctl_t)); | ||
| 2764 | ictl->mode = mode; | ||
| 2765 | ictl->tx_len = mtu; | ||
| 2766 | ictl->irq = card->hw.irq; | ||
| 2767 | |||
| 2768 | /* indicate timeout on timer */ | ||
| 2769 | if (mode & 0x20) ictl->timeout = timeout; | ||
| 2770 | |||
| 2771 | mbox->cmd.length = sizeof(fr508_intr_ctl_t); | ||
| 2772 | mbox->cmd.command = FR_SET_INTR_MODE; | ||
| 2773 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2774 | |||
| 2775 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
| 2776 | |||
| 2777 | return err; | ||
| 2778 | } | ||
| 2779 | |||
| 2780 | /*============================================================================ | ||
| 2781 | * Enable communications. | ||
| 2782 | */ | ||
| 2783 | static int fr_comm_enable (sdla_t* card) | ||
| 2784 | { | ||
| 2785 | fr_mbox_t* mbox = card->mbox; | ||
| 2786 | int retry = MAX_CMD_RETRY; | ||
| 2787 | int err; | ||
| 2788 | |||
| 2789 | do | ||
| 2790 | { | ||
| 2791 | mbox->cmd.command = FR_COMM_ENABLE; | ||
| 2792 | mbox->cmd.length = 0; | ||
| 2793 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2794 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
| 2795 | |||
| 2796 | return err; | ||
| 2797 | } | ||
| 2798 | |||
| 2799 | /*============================================================================ | ||
| 2800 | * fr_comm_disable | ||
| 2801 | * | ||
| 2802 | * Warning: This functin is called by the shutdown() procedure. It is void | ||
| 2803 | * since dev->priv are has already been deallocated and no | ||
| 2804 | * error checking is possible using fr_event() function. | ||
| 2805 | */ | ||
| 2806 | static void fr_comm_disable (sdla_t* card) | ||
| 2807 | { | ||
| 2808 | fr_mbox_t* mbox = card->mbox; | ||
| 2809 | int retry = MAX_CMD_RETRY; | ||
| 2810 | int err; | ||
| 2811 | |||
| 2812 | do { | ||
| 2813 | mbox->cmd.command = FR_SET_MODEM_STATUS; | ||
| 2814 | mbox->cmd.length = 1; | ||
| 2815 | mbox->data[0] = 0; | ||
| 2816 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2817 | } while (err && retry--); | ||
| 2818 | |||
| 2819 | retry = MAX_CMD_RETRY; | ||
| 2820 | |||
| 2821 | do | ||
| 2822 | { | ||
| 2823 | mbox->cmd.command = FR_COMM_DISABLE; | ||
| 2824 | mbox->cmd.length = 0; | ||
| 2825 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2826 | } while (err && retry--); | ||
| 2827 | |||
| 2828 | return; | ||
| 2829 | } | ||
| 2830 | |||
| 2831 | |||
| 2832 | |||
| 2833 | /*============================================================================ | ||
| 2834 | * Get communications error statistics. | ||
| 2835 | */ | ||
| 2836 | static int fr_get_err_stats (sdla_t* card) | ||
| 2837 | { | ||
| 2838 | fr_mbox_t* mbox = card->mbox; | ||
| 2839 | int retry = MAX_CMD_RETRY; | ||
| 2840 | int err; | ||
| 2841 | |||
| 2842 | |||
| 2843 | do | ||
| 2844 | { | ||
| 2845 | mbox->cmd.command = FR_READ_ERROR_STATS; | ||
| 2846 | mbox->cmd.length = 0; | ||
| 2847 | mbox->cmd.dlci = 0; | ||
| 2848 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2849 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
| 2850 | |||
| 2851 | if (!err) { | ||
| 2852 | fr_comm_stat_t* stats = (void*)mbox->data; | ||
| 2853 | card->wandev.stats.rx_over_errors = stats->rx_overruns; | ||
| 2854 | card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; | ||
| 2855 | card->wandev.stats.rx_missed_errors = stats->rx_aborts; | ||
| 2856 | card->wandev.stats.rx_length_errors = stats->rx_too_long; | ||
| 2857 | card->wandev.stats.tx_aborted_errors = stats->tx_aborts; | ||
| 2858 | |||
| 2859 | } | ||
| 2860 | |||
| 2861 | return err; | ||
| 2862 | } | ||
| 2863 | |||
| 2864 | /*============================================================================ | ||
| 2865 | * Get statistics. | ||
| 2866 | */ | ||
| 2867 | static int fr_get_stats (sdla_t* card) | ||
| 2868 | { | ||
| 2869 | fr_mbox_t* mbox = card->mbox; | ||
| 2870 | int retry = MAX_CMD_RETRY; | ||
| 2871 | int err; | ||
| 2872 | |||
| 2873 | |||
| 2874 | do | ||
| 2875 | { | ||
| 2876 | mbox->cmd.command = FR_READ_STATISTICS; | ||
| 2877 | mbox->cmd.length = 0; | ||
| 2878 | mbox->cmd.dlci = 0; | ||
| 2879 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2880 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
| 2881 | |||
| 2882 | if (!err) { | ||
| 2883 | fr_link_stat_t* stats = (void*)mbox->data; | ||
| 2884 | card->wandev.stats.rx_frame_errors = stats->rx_bad_format; | ||
| 2885 | card->wandev.stats.rx_dropped = | ||
| 2886 | stats->rx_dropped + stats->rx_dropped2; | ||
| 2887 | } | ||
| 2888 | |||
| 2889 | return err; | ||
| 2890 | } | ||
| 2891 | |||
| 2892 | /*============================================================================ | ||
| 2893 | * Add DLCI(s) (Access Node only!). | ||
| 2894 | * This routine will perform the ADD_DLCIs command for the specified DLCI. | ||
| 2895 | */ | ||
| 2896 | static int fr_add_dlci (sdla_t* card, int dlci) | ||
| 2897 | { | ||
| 2898 | fr_mbox_t* mbox = card->mbox; | ||
| 2899 | int retry = MAX_CMD_RETRY; | ||
| 2900 | int err; | ||
| 2901 | |||
| 2902 | do | ||
| 2903 | { | ||
| 2904 | unsigned short* dlci_list = (void*)mbox->data; | ||
| 2905 | |||
| 2906 | mbox->cmd.length = sizeof(short); | ||
| 2907 | dlci_list[0] = dlci; | ||
| 2908 | mbox->cmd.command = FR_ADD_DLCI; | ||
| 2909 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2910 | |||
| 2911 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
| 2912 | |||
| 2913 | return err; | ||
| 2914 | } | ||
| 2915 | |||
| 2916 | /*============================================================================ | ||
| 2917 | * Activate DLCI(s) (Access Node only!). | ||
| 2918 | * This routine will perform the ACTIVATE_DLCIs command with a DLCI number. | ||
| 2919 | */ | ||
| 2920 | static int fr_activate_dlci (sdla_t* card, int dlci) | ||
| 2921 | { | ||
| 2922 | fr_mbox_t* mbox = card->mbox; | ||
| 2923 | int retry = MAX_CMD_RETRY; | ||
| 2924 | int err; | ||
| 2925 | |||
| 2926 | do | ||
| 2927 | { | ||
| 2928 | unsigned short* dlci_list = (void*)mbox->data; | ||
| 2929 | |||
| 2930 | mbox->cmd.length = sizeof(short); | ||
| 2931 | dlci_list[0] = dlci; | ||
| 2932 | mbox->cmd.command = FR_ACTIVATE_DLCI; | ||
| 2933 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2934 | |||
| 2935 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
| 2936 | |||
| 2937 | return err; | ||
| 2938 | } | ||
| 2939 | |||
| 2940 | /*============================================================================ | ||
| 2941 | * Delete DLCI(s) (Access Node only!). | ||
| 2942 | * This routine will perform the DELETE_DLCIs command with a DLCI number. | ||
| 2943 | */ | ||
| 2944 | static int fr_delete_dlci (sdla_t* card, int dlci) | ||
| 2945 | { | ||
| 2946 | fr_mbox_t* mbox = card->mbox; | ||
| 2947 | int retry = MAX_CMD_RETRY; | ||
| 2948 | int err; | ||
| 2949 | |||
| 2950 | do | ||
| 2951 | { | ||
| 2952 | unsigned short* dlci_list = (void*)mbox->data; | ||
| 2953 | |||
| 2954 | mbox->cmd.length = sizeof(short); | ||
| 2955 | dlci_list[0] = dlci; | ||
| 2956 | mbox->cmd.command = FR_DELETE_DLCI; | ||
| 2957 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2958 | |||
| 2959 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
| 2960 | |||
| 2961 | return err; | ||
| 2962 | } | ||
| 2963 | |||
| 2964 | |||
| 2965 | |||
| 2966 | /*============================================================================ | ||
| 2967 | * Issue in-channel signalling frame. | ||
| 2968 | */ | ||
| 2969 | static int fr_issue_isf (sdla_t* card, int isf) | ||
| 2970 | { | ||
| 2971 | fr_mbox_t* mbox = card->mbox; | ||
| 2972 | int retry = MAX_CMD_RETRY; | ||
| 2973 | int err; | ||
| 2974 | |||
| 2975 | do | ||
| 2976 | { | ||
| 2977 | mbox->data[0] = isf; | ||
| 2978 | mbox->cmd.length = 1; | ||
| 2979 | mbox->cmd.command = FR_ISSUE_IS_FRAME; | ||
| 2980 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2981 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
| 2982 | |||
| 2983 | return err; | ||
| 2984 | } | ||
| 2985 | |||
| 2986 | |||
| 2987 | static unsigned int fr_send_hdr (sdla_t*card, int dlci, unsigned int offset) | ||
| 2988 | { | ||
| 2989 | struct net_device *dev = find_channel(card,dlci); | ||
| 2990 | fr_channel_t *chan; | ||
| 2991 | |||
| 2992 | if (!dev || !(chan=dev->priv)) | ||
| 2993 | return offset; | ||
| 2994 | |||
| 2995 | if (chan->fr_header_len){ | ||
| 2996 | sdla_poke(&card->hw, offset, chan->fr_header, chan->fr_header_len); | ||
| 2997 | } | ||
| 2998 | |||
| 2999 | return offset+chan->fr_header_len; | ||
| 3000 | } | ||
| 3001 | |||
| 3002 | /*============================================================================ | ||
| 3003 | * Send a frame on a selected DLCI. | ||
| 3004 | */ | ||
| 3005 | static int fr_send_data_header (sdla_t* card, int dlci, unsigned char attr, int len, | ||
| 3006 | void *buf, unsigned char hdr_len) | ||
| 3007 | { | ||
| 3008 | fr_mbox_t* mbox = card->mbox + 0x800; | ||
| 3009 | int retry = MAX_CMD_RETRY; | ||
| 3010 | int err; | ||
| 3011 | |||
| 3012 | do | ||
| 3013 | { | ||
| 3014 | mbox->cmd.dlci = dlci; | ||
| 3015 | mbox->cmd.attr = attr; | ||
| 3016 | mbox->cmd.length = len+hdr_len; | ||
| 3017 | mbox->cmd.command = FR_WRITE; | ||
| 3018 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 3019 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
| 3020 | |||
| 3021 | if (!err) { | ||
| 3022 | fr_tx_buf_ctl_t* frbuf; | ||
| 3023 | |||
| 3024 | if(card->hw.type == SDLA_S514) | ||
| 3025 | frbuf = (void*)(*(unsigned long*)mbox->data + | ||
| 3026 | card->hw.dpmbase); | ||
| 3027 | else | ||
| 3028 | frbuf = (void*)(*(unsigned long*)mbox->data - | ||
| 3029 | FR_MB_VECTOR + card->hw.dpmbase); | ||
| 3030 | |||
| 3031 | sdla_poke(&card->hw, fr_send_hdr(card,dlci,frbuf->offset), buf, len); | ||
| 3032 | frbuf->flag = 0x01; | ||
| 3033 | } | ||
| 3034 | |||
| 3035 | return err; | ||
| 3036 | } | ||
| 3037 | |||
| 3038 | static int fr_send (sdla_t* card, int dlci, unsigned char attr, int len, | ||
| 3039 | void *buf) | ||
| 3040 | { | ||
| 3041 | fr_mbox_t* mbox = card->mbox + 0x800; | ||
| 3042 | int retry = MAX_CMD_RETRY; | ||
| 3043 | int err; | ||
| 3044 | |||
| 3045 | do | ||
| 3046 | { | ||
| 3047 | mbox->cmd.dlci = dlci; | ||
| 3048 | mbox->cmd.attr = attr; | ||
| 3049 | mbox->cmd.length = len; | ||
| 3050 | mbox->cmd.command = FR_WRITE; | ||
| 3051 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 3052 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
| 3053 | |||
| 3054 | if (!err) { | ||
| 3055 | fr_tx_buf_ctl_t* frbuf; | ||
| 3056 | |||
| 3057 | if(card->hw.type == SDLA_S514) | ||
| 3058 | frbuf = (void*)(*(unsigned long*)mbox->data + | ||
| 3059 | card->hw.dpmbase); | ||
| 3060 | else | ||
| 3061 | frbuf = (void*)(*(unsigned long*)mbox->data - | ||
| 3062 | FR_MB_VECTOR + card->hw.dpmbase); | ||
| 3063 | |||
| 3064 | sdla_poke(&card->hw, frbuf->offset, buf, len); | ||
| 3065 | frbuf->flag = 0x01; | ||
| 3066 | } | ||
| 3067 | |||
| 3068 | return err; | ||
| 3069 | } | ||
| 3070 | |||
| 3071 | |||
| 3072 | /****** Firmware Asynchronous Event Handlers ********************************/ | ||
| 3073 | |||
| 3074 | /*============================================================================ | ||
| 3075 | * Main asyncronous event/error handler. | ||
| 3076 | * This routine is called whenever firmware command returns non-zero | ||
| 3077 | * return code. | ||
| 3078 | * | ||
| 3079 | * Return zero if previous command has to be cancelled. | ||
| 3080 | */ | ||
| 3081 | static int fr_event (sdla_t *card, int event, fr_mbox_t* mbox) | ||
| 3082 | { | ||
| 3083 | fr508_flags_t* flags = card->flags; | ||
| 3084 | char *ptr = &flags->iflag; | ||
| 3085 | int i; | ||
| 3086 | |||
| 3087 | switch (event) { | ||
| 3088 | |||
| 3089 | case FRRES_MODEM_FAILURE: | ||
| 3090 | return fr_modem_failure(card, mbox); | ||
| 3091 | |||
| 3092 | case FRRES_CHANNEL_DOWN: { | ||
| 3093 | struct net_device *dev; | ||
| 3094 | |||
| 3095 | /* Remove all routes from associated DLCI's */ | ||
| 3096 | for (dev = card->wandev.dev; dev; | ||
| 3097 | dev = *((struct net_device **)dev->priv)) { | ||
| 3098 | fr_channel_t *chan = dev->priv; | ||
| 3099 | if (chan->route_flag == ROUTE_ADDED) { | ||
| 3100 | chan->route_flag = REMOVE_ROUTE; | ||
| 3101 | } | ||
| 3102 | |||
| 3103 | if (chan->inarp == INARP_CONFIGURED) { | ||
| 3104 | chan->inarp = INARP_REQUEST; | ||
| 3105 | } | ||
| 3106 | |||
| 3107 | /* If the link becomes disconnected then, | ||
| 3108 | * all channels will be disconnected | ||
| 3109 | * as well. | ||
| 3110 | */ | ||
| 3111 | set_chan_state(dev,WAN_DISCONNECTED); | ||
| 3112 | } | ||
| 3113 | |||
| 3114 | wanpipe_set_state(card, WAN_DISCONNECTED); | ||
| 3115 | return 1; | ||
| 3116 | } | ||
| 3117 | |||
| 3118 | case FRRES_CHANNEL_UP: { | ||
| 3119 | struct net_device *dev; | ||
| 3120 | |||
| 3121 | /* FIXME: Only startup devices that are on the list */ | ||
| 3122 | |||
| 3123 | for (dev = card->wandev.dev; dev; | ||
| 3124 | dev = *((struct net_device **)dev->priv)) { | ||
| 3125 | |||
| 3126 | set_chan_state(dev,WAN_CONNECTED); | ||
| 3127 | } | ||
| 3128 | |||
| 3129 | wanpipe_set_state(card, WAN_CONNECTED); | ||
| 3130 | return 1; | ||
| 3131 | } | ||
| 3132 | |||
| 3133 | case FRRES_DLCI_CHANGE: | ||
| 3134 | return fr_dlci_change(card, mbox); | ||
| 3135 | |||
| 3136 | case FRRES_DLCI_MISMATCH: | ||
| 3137 | printk(KERN_INFO "%s: DLCI list mismatch!\n", | ||
| 3138 | card->devname); | ||
| 3139 | return 1; | ||
| 3140 | |||
| 3141 | case CMD_TIMEOUT: | ||
| 3142 | printk(KERN_ERR "%s: command 0x%02X timed out!\n", | ||
| 3143 | card->devname, mbox->cmd.command); | ||
| 3144 | printk(KERN_INFO "%s: ID Bytes = ",card->devname); | ||
| 3145 | for(i = 0; i < 8; i ++) | ||
| 3146 | printk(KERN_INFO "0x%02X ", *(ptr + 0x18 + i)); | ||
| 3147 | printk(KERN_INFO "\n"); | ||
| 3148 | |||
| 3149 | break; | ||
| 3150 | |||
| 3151 | case FRRES_DLCI_INACTIVE: | ||
| 3152 | break; | ||
| 3153 | |||
| 3154 | case FRRES_CIR_OVERFLOW: | ||
| 3155 | break; | ||
| 3156 | |||
| 3157 | case FRRES_BUFFER_OVERFLOW: | ||
| 3158 | break; | ||
| 3159 | |||
| 3160 | default: | ||
| 3161 | printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" | ||
| 3162 | , card->devname, mbox->cmd.command, event); | ||
| 3163 | } | ||
| 3164 | |||
| 3165 | return 0; | ||
| 3166 | } | ||
| 3167 | |||
| 3168 | /*============================================================================ | ||
| 3169 | * Handle modem error. | ||
| 3170 | * | ||
| 3171 | * Return zero if previous command has to be cancelled. | ||
| 3172 | */ | ||
| 3173 | static int fr_modem_failure (sdla_t *card, fr_mbox_t* mbox) | ||
| 3174 | { | ||
| 3175 | printk(KERN_INFO "%s: physical link down! (modem error 0x%02X)\n", | ||
| 3176 | card->devname, mbox->data[0]); | ||
| 3177 | |||
| 3178 | switch (mbox->cmd.command){ | ||
| 3179 | case FR_WRITE: | ||
| 3180 | |||
| 3181 | case FR_READ: | ||
| 3182 | return 0; | ||
| 3183 | } | ||
| 3184 | |||
| 3185 | return 1; | ||
| 3186 | } | ||
| 3187 | |||
| 3188 | /*============================================================================ | ||
| 3189 | * Handle DLCI status change. | ||
| 3190 | * | ||
| 3191 | * Return zero if previous command has to be cancelled. | ||
| 3192 | */ | ||
| 3193 | static int fr_dlci_change (sdla_t *card, fr_mbox_t* mbox) | ||
| 3194 | { | ||
| 3195 | dlci_status_t* status = (void*)mbox->data; | ||
| 3196 | int cnt = mbox->cmd.length / sizeof(dlci_status_t); | ||
| 3197 | fr_channel_t *chan; | ||
| 3198 | struct net_device* dev2; | ||
| 3199 | |||
| 3200 | |||
| 3201 | for (; cnt; --cnt, ++status) { | ||
| 3202 | |||
| 3203 | unsigned short dlci= status->dlci; | ||
| 3204 | struct net_device* dev = find_channel(card, dlci); | ||
| 3205 | |||
| 3206 | if (dev == NULL){ | ||
| 3207 | printk(KERN_INFO | ||
| 3208 | "%s: CPE contains unconfigured DLCI= %d\n", | ||
| 3209 | card->devname, dlci); | ||
| 3210 | |||
| 3211 | printk(KERN_INFO | ||
| 3212 | "%s: unconfigured DLCI %d reported by network\n" | ||
| 3213 | , card->devname, dlci); | ||
| 3214 | |||
| 3215 | }else{ | ||
| 3216 | if (status->state == FR_LINK_INOPER) { | ||
| 3217 | printk(KERN_INFO | ||
| 3218 | "%s: DLCI %u is inactive!\n", | ||
| 3219 | card->devname, dlci); | ||
| 3220 | |||
| 3221 | if (dev && netif_running(dev)) | ||
| 3222 | set_chan_state(dev, WAN_DISCONNECTED); | ||
| 3223 | } | ||
| 3224 | |||
| 3225 | if (status->state & FR_DLCI_DELETED) { | ||
| 3226 | |||
| 3227 | printk(KERN_INFO | ||
| 3228 | "%s: DLCI %u has been deleted!\n", | ||
| 3229 | card->devname, dlci); | ||
| 3230 | |||
| 3231 | if (dev && netif_running(dev)){ | ||
| 3232 | |||
| 3233 | fr_channel_t *chan = dev->priv; | ||
| 3234 | |||
| 3235 | if (chan->route_flag == ROUTE_ADDED) { | ||
| 3236 | chan->route_flag = REMOVE_ROUTE; | ||
| 3237 | /* The state change will trigger | ||
| 3238 | * the fr polling routine */ | ||
| 3239 | } | ||
| 3240 | |||
| 3241 | if (chan->inarp == INARP_CONFIGURED) { | ||
| 3242 | chan->inarp = INARP_REQUEST; | ||
| 3243 | } | ||
| 3244 | |||
| 3245 | set_chan_state(dev, WAN_DISCONNECTED); | ||
| 3246 | } | ||
| 3247 | |||
| 3248 | } else if (status->state & FR_DLCI_ACTIVE) { | ||
| 3249 | |||
| 3250 | chan = dev->priv; | ||
| 3251 | |||
| 3252 | /* This flag is used for configuring specific | ||
| 3253 | DLCI(s) when they become active. | ||
| 3254 | */ | ||
| 3255 | chan->dlci_configured = DLCI_CONFIG_PENDING; | ||
| 3256 | |||
| 3257 | set_chan_state(dev, WAN_CONNECTED); | ||
| 3258 | |||
| 3259 | } | ||
| 3260 | } | ||
| 3261 | } | ||
| 3262 | |||
| 3263 | for (dev2 = card->wandev.dev; dev2; | ||
| 3264 | dev2 = *((struct net_device **)dev2->priv)){ | ||
| 3265 | |||
| 3266 | chan = dev2->priv; | ||
| 3267 | |||
| 3268 | if (chan->dlci_configured == DLCI_CONFIG_PENDING) { | ||
| 3269 | if (fr_init_dlci(card, chan)){ | ||
| 3270 | return 1; | ||
| 3271 | } | ||
| 3272 | } | ||
| 3273 | |||
| 3274 | } | ||
| 3275 | return 1; | ||
| 3276 | } | ||
| 3277 | |||
| 3278 | |||
| 3279 | static int fr_init_dlci (sdla_t *card, fr_channel_t *chan) | ||
| 3280 | { | ||
| 3281 | fr_dlc_conf_t cfg; | ||
| 3282 | |||
| 3283 | memset(&cfg, 0, sizeof(cfg)); | ||
| 3284 | |||
| 3285 | if ( chan->cir_status == CIR_DISABLED) { | ||
| 3286 | |||
| 3287 | cfg.cir_fwd = cfg.cir_bwd = 16; | ||
| 3288 | cfg.bc_fwd = cfg.bc_bwd = 16; | ||
| 3289 | cfg.conf_flags = 0x0001; | ||
| 3290 | |||
| 3291 | }else if (chan->cir_status == CIR_ENABLED) { | ||
| 3292 | |||
| 3293 | cfg.cir_fwd = cfg.cir_bwd = chan->cir; | ||
| 3294 | cfg.bc_fwd = cfg.bc_bwd = chan->bc; | ||
| 3295 | cfg.be_fwd = cfg.be_bwd = chan->be; | ||
| 3296 | cfg.conf_flags = 0x0000; | ||
| 3297 | } | ||
| 3298 | |||
| 3299 | if (fr_dlci_configure( card, &cfg , chan->dlci)){ | ||
| 3300 | printk(KERN_INFO | ||
| 3301 | "%s: DLCI Configure failed for %d\n", | ||
| 3302 | card->devname, chan->dlci); | ||
| 3303 | return 1; | ||
| 3304 | } | ||
| 3305 | |||
| 3306 | chan->dlci_configured = DLCI_CONFIGURED; | ||
| 3307 | |||
| 3308 | /* Read the interface byte mapping into the channel | ||
| 3309 | * structure. | ||
| 3310 | */ | ||
| 3311 | read_DLCI_IB_mapping( card, chan ); | ||
| 3312 | |||
| 3313 | return 0; | ||
| 3314 | } | ||
| 3315 | /******* Miscellaneous ******************************************************/ | ||
| 3316 | |||
| 3317 | /*============================================================================ | ||
| 3318 | * Update channel state. | ||
| 3319 | */ | ||
| 3320 | static int update_chan_state(struct net_device* dev) | ||
| 3321 | { | ||
| 3322 | fr_channel_t* chan = dev->priv; | ||
| 3323 | sdla_t* card = chan->card; | ||
| 3324 | fr_mbox_t* mbox = card->mbox; | ||
| 3325 | int retry = MAX_CMD_RETRY; | ||
| 3326 | int err; | ||
| 3327 | |||
| 3328 | do | ||
| 3329 | { | ||
| 3330 | mbox->cmd.command = FR_LIST_ACTIVE_DLCI; | ||
| 3331 | mbox->cmd.length = 0; | ||
| 3332 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 3333 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
| 3334 | |||
| 3335 | if (!err) { | ||
| 3336 | |||
| 3337 | unsigned short* list = (void*)mbox->data; | ||
| 3338 | int cnt = mbox->cmd.length / sizeof(short); | ||
| 3339 | |||
| 3340 | err=1; | ||
| 3341 | |||
| 3342 | for (; cnt; --cnt, ++list) { | ||
| 3343 | |||
| 3344 | if (*list == chan->dlci) { | ||
| 3345 | set_chan_state(dev, WAN_CONNECTED); | ||
| 3346 | |||
| 3347 | |||
| 3348 | /* May 23 2000. NC | ||
| 3349 | * When a dlci is added or restarted, | ||
| 3350 | * the dlci_int_interface pointer must | ||
| 3351 | * be reinitialized. */ | ||
| 3352 | if (!chan->dlci_int_interface){ | ||
| 3353 | err=fr_init_dlci (card,chan); | ||
| 3354 | } | ||
| 3355 | break; | ||
| 3356 | } | ||
| 3357 | } | ||
| 3358 | } | ||
| 3359 | |||
| 3360 | return err; | ||
| 3361 | } | ||
| 3362 | |||
| 3363 | /*============================================================================ | ||
| 3364 | * Set channel state. | ||
| 3365 | */ | ||
| 3366 | static void set_chan_state(struct net_device* dev, int state) | ||
| 3367 | { | ||
| 3368 | fr_channel_t* chan = dev->priv; | ||
| 3369 | sdla_t* card = chan->card; | ||
| 3370 | |||
| 3371 | if (chan->common.state != state) { | ||
| 3372 | |||
| 3373 | switch (state) { | ||
| 3374 | |||
| 3375 | case WAN_CONNECTED: | ||
| 3376 | printk(KERN_INFO | ||
| 3377 | "%s: Interface %s: DLCI %d connected\n", | ||
| 3378 | card->devname, dev->name, chan->dlci); | ||
| 3379 | |||
| 3380 | /* If the interface was previoulsy down, | ||
| 3381 | * bring it up, since the channel is active */ | ||
| 3382 | |||
| 3383 | trigger_fr_poll (dev); | ||
| 3384 | trigger_fr_arp (dev); | ||
| 3385 | break; | ||
| 3386 | |||
| 3387 | case WAN_CONNECTING: | ||
| 3388 | printk(KERN_INFO | ||
| 3389 | "%s: Interface %s: DLCI %d connecting\n", | ||
| 3390 | card->devname, dev->name, chan->dlci); | ||
| 3391 | break; | ||
| 3392 | |||
| 3393 | case WAN_DISCONNECTED: | ||
| 3394 | printk (KERN_INFO | ||
| 3395 | "%s: Interface %s: DLCI %d disconnected!\n", | ||
| 3396 | card->devname, dev->name, chan->dlci); | ||
| 3397 | |||
| 3398 | /* If the interface is up, bring it down, | ||
| 3399 | * since the channel is now disconnected */ | ||
| 3400 | trigger_fr_poll (dev); | ||
| 3401 | break; | ||
| 3402 | } | ||
| 3403 | |||
| 3404 | chan->common.state = state; | ||
| 3405 | } | ||
| 3406 | |||
| 3407 | chan->state_tick = jiffies; | ||
| 3408 | } | ||
| 3409 | |||
| 3410 | /*============================================================================ | ||
| 3411 | * Find network device by its channel number. | ||
| 3412 | * | ||
| 3413 | * We need this critical flag because we change | ||
| 3414 | * the dlci_to_dev_map outside the interrupt. | ||
| 3415 | * | ||
| 3416 | * NOTE: del_if() functions updates this array, it uses | ||
| 3417 | * the spin locks to avoid corruption. | ||
| 3418 | */ | ||
| 3419 | static struct net_device* find_channel(sdla_t* card, unsigned dlci) | ||
| 3420 | { | ||
| 3421 | if(dlci > HIGHEST_VALID_DLCI) | ||
| 3422 | return NULL; | ||
| 3423 | |||
| 3424 | return(card->u.f.dlci_to_dev_map[dlci]); | ||
| 3425 | } | ||
| 3426 | |||
| 3427 | /*============================================================================ | ||
| 3428 | * Check to see if a frame can be sent. If no transmit buffers available, | ||
| 3429 | * enable transmit interrupts. | ||
| 3430 | * | ||
| 3431 | * Return: 1 - Tx buffer(s) available | ||
| 3432 | * 0 - no buffers available | ||
| 3433 | */ | ||
| 3434 | static int is_tx_ready (sdla_t* card, fr_channel_t* chan) | ||
| 3435 | { | ||
| 3436 | unsigned char sb; | ||
| 3437 | |||
| 3438 | if(card->hw.type == SDLA_S514) | ||
| 3439 | return 1; | ||
| 3440 | |||
| 3441 | sb = inb(card->hw.port); | ||
| 3442 | if (sb & 0x02) | ||
| 3443 | return 1; | ||
| 3444 | |||
| 3445 | return 0; | ||
| 3446 | } | ||
| 3447 | |||
| 3448 | /*============================================================================ | ||
| 3449 | * Convert decimal string to unsigned integer. | ||
| 3450 | * If len != 0 then only 'len' characters of the string are converted. | ||
| 3451 | */ | ||
| 3452 | static unsigned int dec_to_uint (unsigned char* str, int len) | ||
| 3453 | { | ||
| 3454 | unsigned val; | ||
| 3455 | |||
| 3456 | if (!len) | ||
| 3457 | len = strlen(str); | ||
| 3458 | |||
| 3459 | for (val = 0; len && isdigit(*str); ++str, --len) | ||
| 3460 | val = (val * 10) + (*str - (unsigned)'0'); | ||
| 3461 | |||
| 3462 | return val; | ||
| 3463 | } | ||
| 3464 | |||
| 3465 | |||
| 3466 | |||
| 3467 | /*============================================================================= | ||
| 3468 | * Store a UDP management packet for later processing. | ||
| 3469 | */ | ||
| 3470 | |||
| 3471 | static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card, | ||
| 3472 | struct sk_buff *skb, int dlci) | ||
| 3473 | { | ||
| 3474 | int udp_pkt_stored = 0; | ||
| 3475 | |||
| 3476 | struct net_device *dev = find_channel(card, dlci); | ||
| 3477 | fr_channel_t *chan; | ||
| 3478 | |||
| 3479 | if (!dev || !(chan=dev->priv)) | ||
| 3480 | return 1; | ||
| 3481 | |||
| 3482 | if(!card->u.f.udp_pkt_lgth && (skb->len <= MAX_LGTH_UDP_MGNT_PKT)){ | ||
| 3483 | card->u.f.udp_pkt_lgth = skb->len + chan->fr_header_len; | ||
| 3484 | card->u.f.udp_type = udp_type; | ||
| 3485 | card->u.f.udp_pkt_src = udp_pkt_src; | ||
| 3486 | card->u.f.udp_dlci = dlci; | ||
| 3487 | memcpy(card->u.f.udp_pkt_data, skb->data, skb->len); | ||
| 3488 | card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UDP; | ||
| 3489 | udp_pkt_stored = 1; | ||
| 3490 | |||
| 3491 | }else{ | ||
| 3492 | printk(KERN_INFO "ERROR: UDP packet not stored for DLCI %d\n", | ||
| 3493 | dlci); | ||
| 3494 | } | ||
| 3495 | |||
| 3496 | if(udp_pkt_src == UDP_PKT_FRM_STACK){ | ||
| 3497 | dev_kfree_skb_any(skb); | ||
| 3498 | }else{ | ||
| 3499 | dev_kfree_skb_any(skb); | ||
| 3500 | } | ||
| 3501 | |||
| 3502 | return(udp_pkt_stored); | ||
| 3503 | } | ||
| 3504 | |||
| 3505 | |||
| 3506 | /*============================================================================== | ||
| 3507 | * Process UDP call of type FPIPE8ND | ||
| 3508 | */ | ||
| 3509 | static int process_udp_mgmt_pkt(sdla_t* card) | ||
| 3510 | { | ||
| 3511 | |||
| 3512 | int c_retry = MAX_CMD_RETRY; | ||
| 3513 | unsigned char *buf; | ||
| 3514 | unsigned char frames; | ||
| 3515 | unsigned int len; | ||
| 3516 | unsigned short buffer_length; | ||
| 3517 | struct sk_buff *new_skb; | ||
| 3518 | fr_mbox_t* mbox = card->mbox; | ||
| 3519 | int err; | ||
| 3520 | struct timeval tv; | ||
| 3521 | int udp_mgmt_req_valid = 1; | ||
| 3522 | struct net_device* dev; | ||
| 3523 | fr_channel_t* chan; | ||
| 3524 | fr_udp_pkt_t *fr_udp_pkt; | ||
| 3525 | unsigned short num_trc_els; | ||
| 3526 | fr_trc_el_t* ptr_trc_el; | ||
| 3527 | fr_trc_el_t trc_el; | ||
| 3528 | fpipemon_trc_t* fpipemon_trc; | ||
| 3529 | |||
| 3530 | char udp_pkt_src = card->u.f.udp_pkt_src; | ||
| 3531 | int dlci = card->u.f.udp_dlci; | ||
| 3532 | |||
| 3533 | /* Find network interface for this packet */ | ||
| 3534 | dev = find_channel(card, dlci); | ||
| 3535 | if (!dev){ | ||
| 3536 | card->u.f.udp_pkt_lgth = 0; | ||
| 3537 | return 1; | ||
| 3538 | } | ||
| 3539 | if ((chan = dev->priv) == NULL){ | ||
| 3540 | card->u.f.udp_pkt_lgth = 0; | ||
| 3541 | return 1; | ||
| 3542 | } | ||
| 3543 | |||
| 3544 | /* If the UDP packet is from the network, we are going to have to | ||
| 3545 | transmit a response. Before doing so, we must check to see that | ||
| 3546 | we are not currently transmitting a frame (in 'if_send()') and | ||
| 3547 | that we are not already in a 'delayed transmit' state. | ||
| 3548 | */ | ||
| 3549 | if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { | ||
| 3550 | if (check_tx_status(card,dev)){ | ||
| 3551 | card->u.f.udp_pkt_lgth = 0; | ||
| 3552 | return 1; | ||
| 3553 | } | ||
| 3554 | } | ||
| 3555 | |||
| 3556 | fr_udp_pkt = (fr_udp_pkt_t *)card->u.f.udp_pkt_data; | ||
| 3557 | |||
| 3558 | if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { | ||
| 3559 | |||
| 3560 | switch(fr_udp_pkt->cblock.command) { | ||
| 3561 | |||
| 3562 | case FR_READ_MODEM_STATUS: | ||
| 3563 | case FR_READ_STATUS: | ||
| 3564 | case FPIPE_ROUTER_UP_TIME: | ||
| 3565 | case FR_READ_ERROR_STATS: | ||
| 3566 | case FPIPE_DRIVER_STAT_GEN: | ||
| 3567 | case FR_READ_STATISTICS: | ||
| 3568 | case FR_READ_ADD_DLC_STATS: | ||
| 3569 | case FR_READ_CONFIG: | ||
| 3570 | case FR_READ_CODE_VERSION: | ||
| 3571 | udp_mgmt_req_valid = 1; | ||
| 3572 | break; | ||
| 3573 | default: | ||
| 3574 | udp_mgmt_req_valid = 0; | ||
| 3575 | break; | ||
| 3576 | } | ||
| 3577 | } | ||
| 3578 | |||
| 3579 | if(!udp_mgmt_req_valid) { | ||
| 3580 | /* set length to 0 */ | ||
| 3581 | fr_udp_pkt->cblock.length = 0; | ||
| 3582 | /* set return code */ | ||
| 3583 | fr_udp_pkt->cblock.result = 0xCD; | ||
| 3584 | |||
| 3585 | chan->drvstats_gen.UDP_PIPE_mgmt_direction_err ++; | ||
| 3586 | |||
| 3587 | if (net_ratelimit()){ | ||
| 3588 | printk(KERN_INFO | ||
| 3589 | "%s: Warning, Illegal UDP command attempted from network: %x\n", | ||
| 3590 | card->devname,fr_udp_pkt->cblock.command); | ||
| 3591 | } | ||
| 3592 | |||
| 3593 | } else { | ||
| 3594 | |||
| 3595 | switch(fr_udp_pkt->cblock.command) { | ||
| 3596 | |||
| 3597 | case FPIPE_ENABLE_TRACING: | ||
| 3598 | if(!card->TracingEnabled) { | ||
| 3599 | do { | ||
| 3600 | mbox->cmd.command = FR_SET_TRACE_CONFIG; | ||
| 3601 | mbox->cmd.length = 1; | ||
| 3602 | mbox->cmd.dlci = 0x00; | ||
| 3603 | mbox->data[0] = fr_udp_pkt->data[0] | | ||
| 3604 | RESET_TRC; | ||
| 3605 | err = sdla_exec(mbox) ? | ||
| 3606 | mbox->cmd.result : CMD_TIMEOUT; | ||
| 3607 | } while (err && c_retry-- && fr_event(card, err, | ||
| 3608 | mbox)); | ||
| 3609 | |||
| 3610 | if(err) { | ||
| 3611 | card->TracingEnabled = 0; | ||
| 3612 | /* set the return code */ | ||
| 3613 | fr_udp_pkt->cblock.result = | ||
| 3614 | mbox->cmd.result; | ||
| 3615 | mbox->cmd.length = 0; | ||
| 3616 | break; | ||
| 3617 | } | ||
| 3618 | |||
| 3619 | sdla_peek(&card->hw, NO_TRC_ELEMENTS_OFF, | ||
| 3620 | &num_trc_els, 2); | ||
| 3621 | sdla_peek(&card->hw, BASE_TRC_ELEMENTS_OFF, | ||
| 3622 | &card->u.f.trc_el_base, 4); | ||
| 3623 | card->u.f.curr_trc_el = card->u.f.trc_el_base; | ||
| 3624 | card->u.f.trc_el_last = card->u.f.curr_trc_el + | ||
| 3625 | ((num_trc_els - 1) * | ||
| 3626 | sizeof(fr_trc_el_t)); | ||
| 3627 | |||
| 3628 | /* Calculate the maximum trace data area in */ | ||
| 3629 | /* the UDP packet */ | ||
| 3630 | card->u.f.trc_bfr_space=(MAX_LGTH_UDP_MGNT_PKT - | ||
| 3631 | //sizeof(fr_encap_hdr_t) - | ||
| 3632 | sizeof(ip_pkt_t) - | ||
| 3633 | sizeof(udp_pkt_t) - | ||
| 3634 | sizeof(wp_mgmt_t) - | ||
| 3635 | sizeof(cblock_t)); | ||
| 3636 | |||
| 3637 | /* set return code */ | ||
| 3638 | fr_udp_pkt->cblock.result = 0; | ||
| 3639 | |||
| 3640 | } else { | ||
| 3641 | /* set return code to line trace already | ||
| 3642 | enabled */ | ||
| 3643 | fr_udp_pkt->cblock.result = 1; | ||
| 3644 | } | ||
| 3645 | |||
| 3646 | mbox->cmd.length = 0; | ||
| 3647 | card->TracingEnabled = 1; | ||
| 3648 | break; | ||
| 3649 | |||
| 3650 | |||
| 3651 | case FPIPE_DISABLE_TRACING: | ||
| 3652 | if(card->TracingEnabled) { | ||
| 3653 | |||
| 3654 | do { | ||
| 3655 | mbox->cmd.command = FR_SET_TRACE_CONFIG; | ||
| 3656 | mbox->cmd.length = 1; | ||
| 3657 | mbox->cmd.dlci = 0x00; | ||
| 3658 | mbox->data[0] = ~ACTIVATE_TRC; | ||
| 3659 | err = sdla_exec(mbox) ? | ||
| 3660 | mbox->cmd.result : CMD_TIMEOUT; | ||
| 3661 | } while (err && c_retry-- && fr_event(card, err, mbox)); | ||
| 3662 | } | ||
| 3663 | |||
| 3664 | /* set return code */ | ||
| 3665 | fr_udp_pkt->cblock.result = 0; | ||
| 3666 | mbox->cmd.length = 0; | ||
| 3667 | card->TracingEnabled = 0; | ||
| 3668 | break; | ||
| 3669 | |||
| 3670 | case FPIPE_GET_TRACE_INFO: | ||
| 3671 | |||
| 3672 | /* Line trace cannot be performed on the 502 */ | ||
| 3673 | if(!card->TracingEnabled) { | ||
| 3674 | /* set return code */ | ||
| 3675 | fr_udp_pkt->cblock.result = 1; | ||
| 3676 | mbox->cmd.length = 0; | ||
| 3677 | break; | ||
| 3678 | } | ||
| 3679 | |||
| 3680 | ptr_trc_el = (void *)card->u.f.curr_trc_el; | ||
| 3681 | |||
| 3682 | buffer_length = 0; | ||
| 3683 | fr_udp_pkt->data[0x00] = 0x00; | ||
| 3684 | |||
| 3685 | for(frames = 0; frames < MAX_FRMS_TRACED; frames ++) { | ||
| 3686 | |||
| 3687 | sdla_peek(&card->hw, (unsigned long)ptr_trc_el, | ||
| 3688 | (void *)&trc_el.flag, | ||
| 3689 | sizeof(fr_trc_el_t)); | ||
| 3690 | if(trc_el.flag == 0x00) { | ||
| 3691 | break; | ||
| 3692 | } | ||
| 3693 | if((card->u.f.trc_bfr_space - buffer_length) | ||
| 3694 | < sizeof(fpipemon_trc_hdr_t)) { | ||
| 3695 | fr_udp_pkt->data[0x00] |= MORE_TRC_DATA; | ||
| 3696 | break; | ||
| 3697 | } | ||
| 3698 | |||
| 3699 | fpipemon_trc = | ||
| 3700 | (fpipemon_trc_t *)&fr_udp_pkt->data[buffer_length]; | ||
| 3701 | fpipemon_trc->fpipemon_trc_hdr.status = | ||
| 3702 | trc_el.attr; | ||
| 3703 | fpipemon_trc->fpipemon_trc_hdr.tmstamp = | ||
| 3704 | trc_el.tmstamp; | ||
| 3705 | fpipemon_trc->fpipemon_trc_hdr.length = | ||
| 3706 | trc_el.length; | ||
| 3707 | |||
| 3708 | if(!trc_el.offset || !trc_el.length) { | ||
| 3709 | |||
| 3710 | fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x00; | ||
| 3711 | |||
| 3712 | }else if((trc_el.length + sizeof(fpipemon_trc_hdr_t) + 1) > | ||
| 3713 | (card->u.f.trc_bfr_space - buffer_length)){ | ||
| 3714 | |||
| 3715 | fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x00; | ||
| 3716 | fr_udp_pkt->data[0x00] |= MORE_TRC_DATA; | ||
| 3717 | |||
| 3718 | }else { | ||
| 3719 | fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x01; | ||
| 3720 | sdla_peek(&card->hw, trc_el.offset, | ||
| 3721 | fpipemon_trc->data, | ||
| 3722 | trc_el.length); | ||
| 3723 | } | ||
| 3724 | |||
| 3725 | trc_el.flag = 0x00; | ||
| 3726 | sdla_poke(&card->hw, (unsigned long)ptr_trc_el, | ||
| 3727 | &trc_el.flag, 1); | ||
| 3728 | |||
| 3729 | ptr_trc_el ++; | ||
| 3730 | if((void *)ptr_trc_el > card->u.f.trc_el_last) | ||
| 3731 | ptr_trc_el = (void*)card->u.f.trc_el_base; | ||
| 3732 | |||
| 3733 | buffer_length += sizeof(fpipemon_trc_hdr_t); | ||
| 3734 | if(fpipemon_trc->fpipemon_trc_hdr.data_passed) { | ||
| 3735 | buffer_length += trc_el.length; | ||
| 3736 | } | ||
| 3737 | |||
| 3738 | if(fr_udp_pkt->data[0x00] & MORE_TRC_DATA) { | ||
| 3739 | break; | ||
| 3740 | } | ||
| 3741 | } | ||
| 3742 | |||
| 3743 | if(frames == MAX_FRMS_TRACED) { | ||
| 3744 | fr_udp_pkt->data[0x00] |= MORE_TRC_DATA; | ||
| 3745 | } | ||
| 3746 | |||
| 3747 | card->u.f.curr_trc_el = (void *)ptr_trc_el; | ||
| 3748 | |||
| 3749 | /* set the total number of frames passed */ | ||
| 3750 | fr_udp_pkt->data[0x00] |= | ||
| 3751 | ((frames << 1) & (MAX_FRMS_TRACED << 1)); | ||
| 3752 | |||
| 3753 | /* set the data length and return code */ | ||
| 3754 | fr_udp_pkt->cblock.length = mbox->cmd.length = buffer_length; | ||
| 3755 | fr_udp_pkt->cblock.result = 0; | ||
| 3756 | break; | ||
| 3757 | |||
| 3758 | case FPIPE_FT1_READ_STATUS: | ||
| 3759 | sdla_peek(&card->hw, 0xF020, | ||
| 3760 | &fr_udp_pkt->data[0x00] , 2); | ||
| 3761 | fr_udp_pkt->cblock.length = mbox->cmd.length = 2; | ||
| 3762 | fr_udp_pkt->cblock.result = 0; | ||
| 3763 | break; | ||
| 3764 | |||
| 3765 | case FPIPE_FLUSH_DRIVER_STATS: | ||
| 3766 | init_chan_statistics(chan); | ||
| 3767 | init_global_statistics(card); | ||
| 3768 | mbox->cmd.length = 0; | ||
| 3769 | break; | ||
| 3770 | |||
| 3771 | case FPIPE_ROUTER_UP_TIME: | ||
| 3772 | do_gettimeofday(&tv); | ||
| 3773 | chan->router_up_time = tv.tv_sec - | ||
| 3774 | chan->router_start_time; | ||
| 3775 | *(unsigned long *)&fr_udp_pkt->data = | ||
| 3776 | chan->router_up_time; | ||
| 3777 | mbox->cmd.length = fr_udp_pkt->cblock.length = 4; | ||
| 3778 | fr_udp_pkt->cblock.result = 0; | ||
| 3779 | break; | ||
| 3780 | |||
| 3781 | case FPIPE_DRIVER_STAT_IFSEND: | ||
| 3782 | memcpy(fr_udp_pkt->data, | ||
| 3783 | &chan->drvstats_if_send.if_send_entry, | ||
| 3784 | sizeof(if_send_stat_t)); | ||
| 3785 | mbox->cmd.length = fr_udp_pkt->cblock.length =sizeof(if_send_stat_t); | ||
| 3786 | fr_udp_pkt->cblock.result = 0; | ||
| 3787 | break; | ||
| 3788 | |||
| 3789 | case FPIPE_DRIVER_STAT_INTR: | ||
| 3790 | |||
| 3791 | memcpy(fr_udp_pkt->data, | ||
| 3792 | &card->statistics.isr_entry, | ||
| 3793 | sizeof(global_stats_t)); | ||
| 3794 | |||
| 3795 | memcpy(&fr_udp_pkt->data[sizeof(global_stats_t)], | ||
| 3796 | &chan->drvstats_rx_intr.rx_intr_no_socket, | ||
| 3797 | sizeof(rx_intr_stat_t)); | ||
| 3798 | |||
| 3799 | mbox->cmd.length = fr_udp_pkt->cblock.length = | ||
| 3800 | sizeof(global_stats_t) + | ||
| 3801 | sizeof(rx_intr_stat_t); | ||
| 3802 | fr_udp_pkt->cblock.result = 0; | ||
| 3803 | break; | ||
| 3804 | |||
| 3805 | case FPIPE_DRIVER_STAT_GEN: | ||
| 3806 | memcpy(fr_udp_pkt->data, | ||
| 3807 | &chan->drvstats_gen.UDP_PIPE_mgmt_kmalloc_err, | ||
| 3808 | sizeof(pipe_mgmt_stat_t)); | ||
| 3809 | |||
| 3810 | memcpy(&fr_udp_pkt->data[sizeof(pipe_mgmt_stat_t)], | ||
| 3811 | &card->statistics, sizeof(global_stats_t)); | ||
| 3812 | |||
| 3813 | mbox->cmd.length = fr_udp_pkt->cblock.length = sizeof(global_stats_t)+ | ||
| 3814 | sizeof(rx_intr_stat_t); | ||
| 3815 | fr_udp_pkt->cblock.result = 0; | ||
| 3816 | break; | ||
| 3817 | |||
| 3818 | |||
| 3819 | case FR_FT1_STATUS_CTRL: | ||
| 3820 | if(fr_udp_pkt->data[0] == 1) { | ||
| 3821 | if(rCount++ != 0 ){ | ||
| 3822 | fr_udp_pkt->cblock.result = 0; | ||
| 3823 | mbox->cmd.length = 1; | ||
| 3824 | break; | ||
| 3825 | } | ||
| 3826 | } | ||
| 3827 | |||
| 3828 | /* Disable FT1 MONITOR STATUS */ | ||
| 3829 | if(fr_udp_pkt->data[0] == 0) { | ||
| 3830 | if( --rCount != 0) { | ||
| 3831 | fr_udp_pkt->cblock.result = 0; | ||
| 3832 | mbox->cmd.length = 1; | ||
| 3833 | break; | ||
| 3834 | } | ||
| 3835 | } | ||
| 3836 | goto udp_mgmt_dflt; | ||
| 3837 | |||
| 3838 | |||
| 3839 | default: | ||
| 3840 | udp_mgmt_dflt: | ||
| 3841 | do { | ||
| 3842 | memcpy(&mbox->cmd, | ||
| 3843 | &fr_udp_pkt->cblock.command, | ||
| 3844 | sizeof(fr_cmd_t)); | ||
| 3845 | if(mbox->cmd.length) { | ||
| 3846 | memcpy(&mbox->data, | ||
| 3847 | (char *)fr_udp_pkt->data, | ||
| 3848 | mbox->cmd.length); | ||
| 3849 | } | ||
| 3850 | |||
| 3851 | err = sdla_exec(mbox) ? mbox->cmd.result : | ||
| 3852 | CMD_TIMEOUT; | ||
| 3853 | } while (err && c_retry-- && fr_event(card, err, mbox)); | ||
| 3854 | |||
| 3855 | if(!err) | ||
| 3856 | chan->drvstats_gen. | ||
| 3857 | UDP_PIPE_mgmt_adptr_cmnd_OK ++; | ||
| 3858 | else | ||
| 3859 | chan->drvstats_gen. | ||
| 3860 | UDP_PIPE_mgmt_adptr_cmnd_timeout ++; | ||
| 3861 | |||
| 3862 | /* copy the result back to our buffer */ | ||
| 3863 | memcpy(&fr_udp_pkt->cblock.command, | ||
| 3864 | &mbox->cmd, sizeof(fr_cmd_t)); | ||
| 3865 | |||
| 3866 | if(mbox->cmd.length) { | ||
| 3867 | memcpy(&fr_udp_pkt->data, | ||
| 3868 | &mbox->data, mbox->cmd.length); | ||
| 3869 | } | ||
| 3870 | } | ||
| 3871 | } | ||
| 3872 | |||
| 3873 | /* Fill UDP TTL */ | ||
| 3874 | fr_udp_pkt->ip_pkt.ttl = card->wandev.ttl; | ||
| 3875 | len = reply_udp(card->u.f.udp_pkt_data, mbox->cmd.length); | ||
| 3876 | |||
| 3877 | if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { | ||
| 3878 | |||
| 3879 | chan->fr_header_len=2; | ||
| 3880 | chan->fr_header[0]=Q922_UI; | ||
| 3881 | chan->fr_header[1]=NLPID_IP; | ||
| 3882 | |||
| 3883 | err = fr_send_data_header(card, dlci, 0, len, | ||
| 3884 | card->u.f.udp_pkt_data,chan->fr_header_len); | ||
| 3885 | if (err){ | ||
| 3886 | chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_passed ++; | ||
| 3887 | }else{ | ||
| 3888 | chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_failed ++; | ||
| 3889 | } | ||
| 3890 | |||
| 3891 | } else { | ||
| 3892 | /* Allocate socket buffer */ | ||
| 3893 | if((new_skb = dev_alloc_skb(len)) != NULL) { | ||
| 3894 | |||
| 3895 | /* copy data into new_skb */ | ||
| 3896 | buf = skb_put(new_skb, len); | ||
| 3897 | memcpy(buf, card->u.f.udp_pkt_data, len); | ||
| 3898 | |||
| 3899 | chan->drvstats_gen. | ||
| 3900 | UDP_PIPE_mgmt_passed_to_stack ++; | ||
| 3901 | new_skb->dev = dev; | ||
| 3902 | new_skb->protocol = htons(ETH_P_IP); | ||
| 3903 | new_skb->mac.raw = new_skb->data; | ||
| 3904 | netif_rx(new_skb); | ||
| 3905 | |||
| 3906 | } else { | ||
| 3907 | chan->drvstats_gen.UDP_PIPE_mgmt_no_socket ++; | ||
| 3908 | printk(KERN_INFO | ||
| 3909 | "%s: UDP mgmt cmnd, no socket buffers available!\n", | ||
| 3910 | card->devname); | ||
| 3911 | } | ||
| 3912 | } | ||
| 3913 | |||
| 3914 | card->u.f.udp_pkt_lgth = 0; | ||
| 3915 | |||
| 3916 | return 1; | ||
| 3917 | } | ||
| 3918 | |||
| 3919 | /*============================================================================== | ||
| 3920 | * Send Inverse ARP Request | ||
| 3921 | */ | ||
| 3922 | |||
| 3923 | int send_inarp_request(sdla_t *card, struct net_device *dev) | ||
| 3924 | { | ||
| 3925 | int err=0; | ||
| 3926 | |||
| 3927 | arphdr_1490_t *ArpPacket; | ||
| 3928 | arphdr_fr_t *arphdr; | ||
| 3929 | fr_channel_t *chan = dev->priv; | ||
| 3930 | struct in_device *in_dev; | ||
| 3931 | |||
| 3932 | in_dev = dev->ip_ptr; | ||
| 3933 | |||
| 3934 | if(in_dev != NULL ) { | ||
| 3935 | |||
| 3936 | ArpPacket = kmalloc(sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), GFP_ATOMIC); | ||
| 3937 | /* SNAP Header indicating ARP */ | ||
| 3938 | ArpPacket->control = 0x03; | ||
| 3939 | ArpPacket->pad = 0x00; | ||
| 3940 | ArpPacket->NLPID = 0x80; | ||
| 3941 | ArpPacket->OUI[0] = 0; | ||
| 3942 | ArpPacket->OUI[1] = 0; | ||
| 3943 | ArpPacket->OUI[2] = 0; | ||
| 3944 | ArpPacket->PID = 0x0608; | ||
| 3945 | |||
| 3946 | arphdr = (arphdr_fr_t *)(ArpPacket + 1); // Go to ARP Packet | ||
| 3947 | |||
| 3948 | /* InARP request */ | ||
| 3949 | arphdr->ar_hrd = 0x0F00; /* Frame Relay HW type */ | ||
| 3950 | arphdr->ar_pro = 0x0008; /* IP Protocol */ | ||
| 3951 | arphdr->ar_hln = 2; /* HW addr length */ | ||
| 3952 | arphdr->ar_pln = 4; /* IP addr length */ | ||
| 3953 | arphdr->ar_op = htons(0x08); /* InARP Request */ | ||
| 3954 | arphdr->ar_sha = 0; /* src HW DLCI - Doesn't matter */ | ||
| 3955 | if(in_dev->ifa_list != NULL) | ||
| 3956 | arphdr->ar_sip = in_dev->ifa_list->ifa_local; /* Local Address */else | ||
| 3957 | arphdr->ar_sip = 0; | ||
| 3958 | arphdr->ar_tha = 0; /* dst HW DLCI - Doesn't matter */ | ||
| 3959 | arphdr->ar_tip = 0; /* Remote Address -- what we want */ | ||
| 3960 | |||
| 3961 | err = fr_send(card, chan->dlci, 0, sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), | ||
| 3962 | (void *)ArpPacket); | ||
| 3963 | |||
| 3964 | if (!err){ | ||
| 3965 | printk(KERN_INFO "\n%s: Sending InARP request on DLCI %d.\n", | ||
| 3966 | card->devname, chan->dlci); | ||
| 3967 | clear_bit(ARP_CRIT,&card->wandev.critical); | ||
| 3968 | } | ||
| 3969 | |||
| 3970 | kfree(ArpPacket); | ||
| 3971 | }else{ | ||
| 3972 | printk(KERN_INFO "%s: INARP ERROR: %s doesn't have a local IP address!\n", | ||
| 3973 | card->devname,dev->name); | ||
| 3974 | return 1; | ||
| 3975 | } | ||
| 3976 | |||
| 3977 | return 0; | ||
| 3978 | } | ||
| 3979 | |||
| 3980 | |||
| 3981 | /*============================================================================== | ||
| 3982 | * Check packet for ARP Type | ||
| 3983 | */ | ||
| 3984 | |||
| 3985 | int is_arp(void *buf) | ||
| 3986 | { | ||
| 3987 | arphdr_1490_t *arphdr = (arphdr_1490_t *)buf; | ||
| 3988 | |||
| 3989 | if (arphdr->pad == 0x00 && | ||
| 3990 | arphdr->NLPID == 0x80 && | ||
| 3991 | arphdr->PID == 0x0608) | ||
| 3992 | return 1; | ||
| 3993 | else return 0; | ||
| 3994 | } | ||
| 3995 | |||
| 3996 | /*============================================================================== | ||
| 3997 | * Process ARP Packet Type | ||
| 3998 | */ | ||
| 3999 | |||
| 4000 | int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct net_device* dev) | ||
| 4001 | { | ||
| 4002 | |||
| 4003 | |||
| 4004 | arphdr_fr_t *arphdr = (arphdr_fr_t *)(ArpPacket + 1); /* Skip header */ | ||
| 4005 | fr_rx_buf_ctl_t* frbuf = card->rxmb; | ||
| 4006 | struct in_device *in_dev; | ||
| 4007 | fr_channel_t *chan = dev->priv; | ||
| 4008 | |||
| 4009 | /* Before we transmit ARP packet, we must check | ||
| 4010 | * to see that we are not currently transmitting a | ||
| 4011 | * frame (in 'if_send()') and that we are not | ||
| 4012 | * already in a 'delayed transmit' state. */ | ||
| 4013 | if (check_tx_status(card,dev)){ | ||
| 4014 | if (net_ratelimit()){ | ||
| 4015 | printk(KERN_INFO "%s: Disabling comminication to process ARP\n", | ||
| 4016 | card->devname); | ||
| 4017 | } | ||
| 4018 | set_bit(ARP_CRIT,&card->wandev.critical); | ||
| 4019 | return 0; | ||
| 4020 | } | ||
| 4021 | |||
| 4022 | in_dev = dev->ip_ptr; | ||
| 4023 | |||
| 4024 | /* Check that IP addresses exist for our network address */ | ||
| 4025 | if (in_dev == NULL || in_dev->ifa_list == NULL) | ||
| 4026 | return -1; | ||
| 4027 | |||
| 4028 | switch (ntohs(arphdr->ar_op)) { | ||
| 4029 | |||
| 4030 | case 0x08: // Inverse ARP request -- Send Reply, add route. | ||
| 4031 | |||
| 4032 | /* Check for valid Address */ | ||
| 4033 | printk(KERN_INFO "%s: Recvd PtP addr -InArp Req: %u.%u.%u.%u\n", | ||
| 4034 | card->devname, NIPQUAD(arphdr->ar_sip)); | ||
| 4035 | |||
| 4036 | |||
| 4037 | /* Check that the network address is the same as ours, only | ||
| 4038 | * if the netowrk mask is not 255.255.255.255. Otherwise | ||
| 4039 | * this check would not make sense */ | ||
| 4040 | |||
| 4041 | if (in_dev->ifa_list->ifa_mask != 0xFFFFFFFF && | ||
| 4042 | (in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != | ||
| 4043 | (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)){ | ||
| 4044 | printk(KERN_INFO | ||
| 4045 | "%s: Invalid PtP address. %u.%u.%u.%u InARP ignored.\n", | ||
| 4046 | card->devname,NIPQUAD(arphdr->ar_sip)); | ||
| 4047 | |||
| 4048 | printk(KERN_INFO "%s: mask %u.%u.%u.%u\n", | ||
| 4049 | card->devname, NIPQUAD(in_dev->ifa_list->ifa_mask)); | ||
| 4050 | printk(KERN_INFO "%s: local %u.%u.%u.%u\n", | ||
| 4051 | card->devname,NIPQUAD(in_dev->ifa_list->ifa_local)); | ||
| 4052 | return -1; | ||
| 4053 | } | ||
| 4054 | |||
| 4055 | if (in_dev->ifa_list->ifa_local == arphdr->ar_sip){ | ||
| 4056 | printk(KERN_INFO | ||
| 4057 | "%s: Local addr = PtP addr. InARP ignored.\n", | ||
| 4058 | card->devname); | ||
| 4059 | return -1; | ||
| 4060 | } | ||
| 4061 | |||
| 4062 | arphdr->ar_op = htons(0x09); /* InARP Reply */ | ||
| 4063 | |||
| 4064 | /* Set addresses */ | ||
| 4065 | arphdr->ar_tip = arphdr->ar_sip; | ||
| 4066 | arphdr->ar_sip = in_dev->ifa_list->ifa_local; | ||
| 4067 | |||
| 4068 | chan->ip_local = in_dev->ifa_list->ifa_local; | ||
| 4069 | chan->ip_remote = arphdr->ar_sip; | ||
| 4070 | |||
| 4071 | fr_send(card, frbuf->dlci, 0, frbuf->length, (void *)ArpPacket); | ||
| 4072 | |||
| 4073 | if (test_bit(ARP_CRIT,&card->wandev.critical)){ | ||
| 4074 | if (net_ratelimit()){ | ||
| 4075 | printk(KERN_INFO "%s: ARP Processed Enabling Communication!\n", | ||
| 4076 | card->devname); | ||
| 4077 | } | ||
| 4078 | } | ||
| 4079 | clear_bit(ARP_CRIT,&card->wandev.critical); | ||
| 4080 | |||
| 4081 | chan->ip_local = in_dev->ifa_list->ifa_local; | ||
| 4082 | chan->ip_remote = arphdr->ar_sip; | ||
| 4083 | |||
| 4084 | /* Add Route Flag */ | ||
| 4085 | /* The route will be added in the polling routine so | ||
| 4086 | that it is not interrupt context. */ | ||
| 4087 | |||
| 4088 | chan->route_flag = ADD_ROUTE; | ||
| 4089 | trigger_fr_poll (dev); | ||
| 4090 | |||
| 4091 | break; | ||
| 4092 | |||
| 4093 | case 0x09: // Inverse ARP reply | ||
| 4094 | |||
| 4095 | /* Check for valid Address */ | ||
| 4096 | printk(KERN_INFO "%s: Recvd PtP addr %u.%u.%u.%u -InArp Reply\n", | ||
| 4097 | card->devname, NIPQUAD(arphdr->ar_sip)); | ||
| 4098 | |||
| 4099 | |||
| 4100 | /* Compare network addresses, only if network mask | ||
| 4101 | * is not 255.255.255.255 It would not make sense | ||
| 4102 | * to perform this test if the mask was all 1's */ | ||
| 4103 | |||
| 4104 | if (in_dev->ifa_list->ifa_mask != 0xffffffff && | ||
| 4105 | (in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != | ||
| 4106 | (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) { | ||
| 4107 | |||
| 4108 | printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n", | ||
| 4109 | card->devname); | ||
| 4110 | return -1; | ||
| 4111 | } | ||
| 4112 | |||
| 4113 | /* Make sure that the received IP address is not | ||
| 4114 | * the same as our own local address */ | ||
| 4115 | if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) { | ||
| 4116 | printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n", | ||
| 4117 | card->devname); | ||
| 4118 | return -1; | ||
| 4119 | } | ||
| 4120 | |||
| 4121 | chan->ip_local = in_dev->ifa_list->ifa_local; | ||
| 4122 | chan->ip_remote = arphdr->ar_sip; | ||
| 4123 | |||
| 4124 | /* Add Route Flag */ | ||
| 4125 | /* The route will be added in the polling routine so | ||
| 4126 | that it is not interrupt context. */ | ||
| 4127 | |||
| 4128 | chan->route_flag = ADD_ROUTE; | ||
| 4129 | chan->inarp = INARP_CONFIGURED; | ||
| 4130 | trigger_fr_poll(dev); | ||
| 4131 | |||
| 4132 | break; | ||
| 4133 | default: | ||
| 4134 | break; // ARP's and RARP's -- Shouldn't happen. | ||
| 4135 | } | ||
| 4136 | |||
| 4137 | return 0; | ||
| 4138 | } | ||
| 4139 | |||
| 4140 | |||
| 4141 | /*============================================================ | ||
| 4142 | * trigger_fr_arp | ||
| 4143 | * | ||
| 4144 | * Description: | ||
| 4145 | * Add an fr_arp() task into a arp | ||
| 4146 | * timer handler for a specific dlci/interface. | ||
| 4147 | * This will kick the fr_arp() routine | ||
| 4148 | * within the specified time interval. | ||
| 4149 | * | ||
| 4150 | * Usage: | ||
| 4151 | * This timer is used to send ARP requests at | ||
| 4152 | * certain time intervals. | ||
| 4153 | * Called by an interrupt to request an action | ||
| 4154 | * at a later date. | ||
| 4155 | */ | ||
| 4156 | |||
| 4157 | static void trigger_fr_arp(struct net_device *dev) | ||
| 4158 | { | ||
| 4159 | fr_channel_t* chan = dev->priv; | ||
| 4160 | |||
| 4161 | mod_timer(&chan->fr_arp_timer, jiffies + chan->inarp_interval * HZ); | ||
| 4162 | return; | ||
| 4163 | } | ||
| 4164 | |||
| 4165 | |||
| 4166 | |||
| 4167 | /*============================================================================== | ||
| 4168 | * ARP Request Action | ||
| 4169 | * | ||
| 4170 | * This funciton is called by timer interrupt to send an arp request | ||
| 4171 | * to the remote end. | ||
| 4172 | */ | ||
| 4173 | |||
| 4174 | static void fr_arp (unsigned long data) | ||
| 4175 | { | ||
| 4176 | struct net_device *dev = (struct net_device *)data; | ||
| 4177 | fr_channel_t *chan = dev->priv; | ||
| 4178 | volatile sdla_t *card = chan->card; | ||
| 4179 | fr508_flags_t* flags = card->flags; | ||
| 4180 | |||
| 4181 | /* Send ARP packets for all devs' until | ||
| 4182 | * ARP state changes to CONFIGURED */ | ||
| 4183 | |||
| 4184 | if (chan->inarp == INARP_REQUEST && | ||
| 4185 | chan->common.state == WAN_CONNECTED && | ||
| 4186 | card->wandev.state == WAN_CONNECTED){ | ||
| 4187 | set_bit(0,&chan->inarp_ready); | ||
| 4188 | card->u.f.timer_int_enabled |= TMR_INT_ENABLED_ARP; | ||
| 4189 | flags->imask |= FR_INTR_TIMER; | ||
| 4190 | } | ||
| 4191 | |||
| 4192 | return; | ||
| 4193 | } | ||
| 4194 | |||
| 4195 | |||
| 4196 | /*============================================================================== | ||
| 4197 | * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR_ | ||
| 4198 | * TEST_COUNTER times. | ||
| 4199 | */ | ||
| 4200 | static int intr_test( sdla_t* card ) | ||
| 4201 | { | ||
| 4202 | fr_mbox_t* mb = card->mbox; | ||
| 4203 | int err,i; | ||
| 4204 | |||
| 4205 | err = fr_set_intr_mode(card, FR_INTR_READY, card->wandev.mtu, 0 ); | ||
| 4206 | |||
| 4207 | if (err == CMD_OK) { | ||
| 4208 | |||
| 4209 | for ( i = 0; i < MAX_INTR_TEST_COUNTER; i++ ) { | ||
| 4210 | /* Run command READ_CODE_VERSION */ | ||
| 4211 | mb->cmd.length = 0; | ||
| 4212 | mb->cmd.command = FR_READ_CODE_VERSION; | ||
| 4213 | err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; | ||
| 4214 | if (err != CMD_OK) | ||
| 4215 | fr_event(card, err, mb); | ||
| 4216 | } | ||
| 4217 | |||
| 4218 | } else { | ||
| 4219 | return err; | ||
| 4220 | } | ||
| 4221 | |||
| 4222 | err = fr_set_intr_mode( card, 0, card->wandev.mtu, 0 ); | ||
| 4223 | |||
| 4224 | if( err != CMD_OK ) | ||
| 4225 | return err; | ||
| 4226 | |||
| 4227 | return 0; | ||
| 4228 | } | ||
| 4229 | |||
| 4230 | /*============================================================================== | ||
| 4231 | * Determine what type of UDP call it is. FPIPE8ND ? | ||
| 4232 | */ | ||
| 4233 | static int udp_pkt_type( struct sk_buff *skb, sdla_t* card ) | ||
| 4234 | { | ||
| 4235 | fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)skb->data; | ||
| 4236 | |||
| 4237 | /* Quick HACK */ | ||
| 4238 | |||
| 4239 | |||
| 4240 | if((fr_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && | ||
| 4241 | (fr_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45) && | ||
| 4242 | (fr_udp_pkt->udp_pkt.udp_dst_port == | ||
| 4243 | ntohs(card->wandev.udp_port)) && | ||
| 4244 | (fr_udp_pkt->wp_mgmt.request_reply == | ||
| 4245 | UDPMGMT_REQUEST)) { | ||
| 4246 | if(!strncmp(fr_udp_pkt->wp_mgmt.signature, | ||
| 4247 | UDPMGMT_FPIPE_SIGNATURE, 8)){ | ||
| 4248 | return UDP_FPIPE_TYPE; | ||
| 4249 | } | ||
| 4250 | } | ||
| 4251 | return UDP_INVALID_TYPE; | ||
| 4252 | } | ||
| 4253 | |||
| 4254 | |||
| 4255 | /*============================================================================== | ||
| 4256 | * Initializes the Statistics values in the fr_channel structure. | ||
| 4257 | */ | ||
| 4258 | void init_chan_statistics( fr_channel_t* chan) | ||
| 4259 | { | ||
| 4260 | memset(&chan->drvstats_if_send.if_send_entry, 0, | ||
| 4261 | sizeof(if_send_stat_t)); | ||
| 4262 | memset(&chan->drvstats_rx_intr.rx_intr_no_socket, 0, | ||
| 4263 | sizeof(rx_intr_stat_t)); | ||
| 4264 | memset(&chan->drvstats_gen.UDP_PIPE_mgmt_kmalloc_err, 0, | ||
| 4265 | sizeof(pipe_mgmt_stat_t)); | ||
| 4266 | } | ||
| 4267 | |||
| 4268 | /*============================================================================== | ||
| 4269 | * Initializes the Statistics values in the Sdla_t structure. | ||
| 4270 | */ | ||
| 4271 | void init_global_statistics( sdla_t* card ) | ||
| 4272 | { | ||
| 4273 | /* Intialize global statistics for a card */ | ||
| 4274 | memset(&card->statistics.isr_entry, 0, sizeof(global_stats_t)); | ||
| 4275 | } | ||
| 4276 | |||
| 4277 | static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan ) | ||
| 4278 | { | ||
| 4279 | fr_mbox_t* mbox = card->mbox; | ||
| 4280 | int retry = MAX_CMD_RETRY; | ||
| 4281 | dlci_IB_mapping_t* result; | ||
| 4282 | int err, counter, found; | ||
| 4283 | |||
| 4284 | do { | ||
| 4285 | mbox->cmd.command = FR_READ_DLCI_IB_MAPPING; | ||
| 4286 | mbox->cmd.length = 0; | ||
| 4287 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 4288 | } while (err && retry-- && fr_event(card, err, mbox)); | ||
| 4289 | |||
| 4290 | if( mbox->cmd.result != 0){ | ||
| 4291 | printk(KERN_INFO "%s: Read DLCI IB Mapping failed\n", | ||
| 4292 | chan->name); | ||
| 4293 | } | ||
| 4294 | |||
| 4295 | counter = mbox->cmd.length / sizeof(dlci_IB_mapping_t); | ||
| 4296 | result = (void *)mbox->data; | ||
| 4297 | |||
| 4298 | found = 0; | ||
| 4299 | for (; counter; --counter, ++result) { | ||
| 4300 | if ( result->dlci == chan->dlci ) { | ||
| 4301 | chan->IB_addr = result->addr_value; | ||
| 4302 | if(card->hw.type == SDLA_S514){ | ||
| 4303 | chan->dlci_int_interface = | ||
| 4304 | (void*)(card->hw.dpmbase + | ||
| 4305 | chan->IB_addr); | ||
| 4306 | }else{ | ||
| 4307 | chan->dlci_int_interface = | ||
| 4308 | (void*)(card->hw.dpmbase + | ||
| 4309 | (chan->IB_addr & 0x00001FFF)); | ||
| 4310 | |||
| 4311 | } | ||
| 4312 | found = 1; | ||
| 4313 | break; | ||
| 4314 | } | ||
| 4315 | } | ||
| 4316 | if (!found) | ||
| 4317 | printk( KERN_INFO "%s: DLCI %d not found by IB MAPPING cmd\n", | ||
| 4318 | card->devname, chan->dlci); | ||
| 4319 | } | ||
| 4320 | |||
| 4321 | |||
| 4322 | |||
| 4323 | void s508_s514_lock(sdla_t *card, unsigned long *smp_flags) | ||
| 4324 | { | ||
| 4325 | if (card->hw.type != SDLA_S514){ | ||
| 4326 | |||
| 4327 | spin_lock_irqsave(&card->wandev.lock, *smp_flags); | ||
| 4328 | }else{ | ||
| 4329 | spin_lock(&card->u.f.if_send_lock); | ||
| 4330 | } | ||
| 4331 | return; | ||
| 4332 | } | ||
| 4333 | |||
| 4334 | |||
| 4335 | void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags) | ||
| 4336 | { | ||
| 4337 | if (card->hw.type != SDLA_S514){ | ||
| 4338 | |||
| 4339 | spin_unlock_irqrestore (&card->wandev.lock, *smp_flags); | ||
| 4340 | }else{ | ||
| 4341 | spin_unlock(&card->u.f.if_send_lock); | ||
| 4342 | } | ||
| 4343 | return; | ||
| 4344 | } | ||
| 4345 | |||
| 4346 | |||
| 4347 | |||
| 4348 | /*---------------------------------------------------------------------- | ||
| 4349 | RECEIVE INTERRUPT: BOTTOM HALF HANDLERS | ||
| 4350 | ----------------------------------------------------------------------*/ | ||
| 4351 | |||
| 4352 | |||
| 4353 | /*======================================================== | ||
| 4354 | * bh_enqueue | ||
| 4355 | * | ||
| 4356 | * Description: | ||
| 4357 | * Insert a received packet into a circular | ||
| 4358 | * rx queue. This packet will be picked up | ||
| 4359 | * by fr_bh() and sent up the stack to the | ||
| 4360 | * user. | ||
| 4361 | * | ||
| 4362 | * Usage: | ||
| 4363 | * This function is called by rx interrupt, | ||
| 4364 | * in API mode. | ||
| 4365 | * | ||
| 4366 | */ | ||
| 4367 | |||
| 4368 | static int bh_enqueue(struct net_device *dev, struct sk_buff *skb) | ||
| 4369 | { | ||
| 4370 | /* Check for full */ | ||
| 4371 | fr_channel_t* chan = dev->priv; | ||
| 4372 | sdla_t *card = chan->card; | ||
| 4373 | |||
| 4374 | |||
| 4375 | if (atomic_read(&chan->bh_buff_used) == MAX_BH_BUFF){ | ||
| 4376 | ++card->wandev.stats.rx_dropped; | ||
| 4377 | dev_kfree_skb_any(skb); | ||
| 4378 | return 1; | ||
| 4379 | } | ||
| 4380 | |||
| 4381 | ((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb; | ||
| 4382 | |||
| 4383 | if (chan->bh_write == (MAX_BH_BUFF-1)){ | ||
| 4384 | chan->bh_write=0; | ||
| 4385 | }else{ | ||
| 4386 | ++chan->bh_write; | ||
| 4387 | } | ||
| 4388 | |||
| 4389 | atomic_inc(&chan->bh_buff_used); | ||
| 4390 | |||
| 4391 | return 0; | ||
| 4392 | } | ||
| 4393 | |||
| 4394 | |||
| 4395 | /*======================================================== | ||
| 4396 | * trigger_fr_bh | ||
| 4397 | * | ||
| 4398 | * Description: | ||
| 4399 | * Kick the fr_bh() handler | ||
| 4400 | * | ||
| 4401 | * Usage: | ||
| 4402 | * rx interrupt calls this function during | ||
| 4403 | * the API mode. | ||
| 4404 | */ | ||
| 4405 | |||
| 4406 | static void trigger_fr_bh (fr_channel_t *chan) | ||
| 4407 | { | ||
| 4408 | if (!test_and_set_bit(0,&chan->tq_working)){ | ||
| 4409 | wanpipe_queue_work(&chan->common.wanpipe_work); | ||
| 4410 | } | ||
| 4411 | } | ||
| 4412 | |||
| 4413 | |||
| 4414 | /*======================================================== | ||
| 4415 | * fr_bh | ||
| 4416 | * | ||
| 4417 | * Description: | ||
| 4418 | * Frame relay receive BH handler. | ||
| 4419 | * Dequeue data from the BH circular | ||
| 4420 | * buffer and pass it up the API sock. | ||
| 4421 | * | ||
| 4422 | * Rationale: | ||
| 4423 | * This fuction is used to offload the | ||
| 4424 | * rx_interrupt during API operation mode. | ||
| 4425 | * The fr_bh() function executes for each | ||
| 4426 | * dlci/interface. | ||
| 4427 | * | ||
| 4428 | * Once receive interrupt copies data from the | ||
| 4429 | * card into an skb buffer, the skb buffer | ||
| 4430 | * is appended to a circular BH buffer. | ||
| 4431 | * Then the interrupt kicks fr_bh() to finish the | ||
| 4432 | * job at a later time (not within the interrupt). | ||
| 4433 | * | ||
| 4434 | * Usage: | ||
| 4435 | * Interrupts use this to defer a task to | ||
| 4436 | * a polling routine. | ||
| 4437 | * | ||
| 4438 | */ | ||
| 4439 | |||
| 4440 | static void fr_bh(struct net_device * dev) | ||
| 4441 | { | ||
| 4442 | fr_channel_t* chan = dev->priv; | ||
| 4443 | sdla_t *card = chan->card; | ||
| 4444 | struct sk_buff *skb; | ||
| 4445 | |||
| 4446 | if (atomic_read(&chan->bh_buff_used) == 0){ | ||
| 4447 | clear_bit(0, &chan->tq_working); | ||
| 4448 | return; | ||
| 4449 | } | ||
| 4450 | |||
| 4451 | while (atomic_read(&chan->bh_buff_used)){ | ||
| 4452 | |||
| 4453 | if (chan->common.sk == NULL || chan->common.func == NULL){ | ||
| 4454 | clear_bit(0, &chan->tq_working); | ||
| 4455 | return; | ||
| 4456 | } | ||
| 4457 | |||
| 4458 | skb = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb; | ||
| 4459 | |||
| 4460 | if (skb != NULL){ | ||
| 4461 | |||
| 4462 | if (chan->common.sk == NULL || chan->common.func == NULL){ | ||
| 4463 | ++card->wandev.stats.rx_dropped; | ||
| 4464 | ++chan->ifstats.rx_dropped; | ||
| 4465 | dev_kfree_skb_any(skb); | ||
| 4466 | fr_bh_cleanup(dev); | ||
| 4467 | continue; | ||
| 4468 | } | ||
| 4469 | |||
| 4470 | if (chan->common.func(skb,dev,chan->common.sk) != 0){ | ||
| 4471 | /* Sock full cannot send, queue us for | ||
| 4472 | * another try */ | ||
| 4473 | atomic_set(&chan->common.receive_block,1); | ||
| 4474 | return; | ||
| 4475 | }else{ | ||
| 4476 | fr_bh_cleanup(dev); | ||
| 4477 | } | ||
| 4478 | }else{ | ||
| 4479 | fr_bh_cleanup(dev); | ||
| 4480 | } | ||
| 4481 | } | ||
| 4482 | clear_bit(0, &chan->tq_working); | ||
| 4483 | |||
| 4484 | return; | ||
| 4485 | } | ||
| 4486 | |||
| 4487 | static int fr_bh_cleanup(struct net_device *dev) | ||
| 4488 | { | ||
| 4489 | fr_channel_t* chan = dev->priv; | ||
| 4490 | |||
| 4491 | ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL; | ||
| 4492 | |||
| 4493 | if (chan->bh_read == (MAX_BH_BUFF-1)){ | ||
| 4494 | chan->bh_read=0; | ||
| 4495 | }else{ | ||
| 4496 | ++chan->bh_read; | ||
| 4497 | } | ||
| 4498 | |||
| 4499 | atomic_dec(&chan->bh_buff_used); | ||
| 4500 | return 0; | ||
| 4501 | } | ||
| 4502 | |||
| 4503 | |||
| 4504 | /*---------------------------------------------------------------------- | ||
| 4505 | POLL BH HANDLERS AND KICK ROUTINES | ||
| 4506 | ----------------------------------------------------------------------*/ | ||
| 4507 | |||
| 4508 | /*============================================================ | ||
| 4509 | * trigger_fr_poll | ||
| 4510 | * | ||
| 4511 | * Description: | ||
| 4512 | * Add a fr_poll() task into a tq_scheduler bh handler | ||
| 4513 | * for a specific dlci/interface. This will kick | ||
| 4514 | * the fr_poll() routine at a later time. | ||
| 4515 | * | ||
| 4516 | * Usage: | ||
| 4517 | * Interrupts use this to defer a taks to | ||
| 4518 | * a polling routine. | ||
| 4519 | * | ||
| 4520 | */ | ||
| 4521 | static void trigger_fr_poll(struct net_device *dev) | ||
| 4522 | { | ||
| 4523 | fr_channel_t* chan = dev->priv; | ||
| 4524 | schedule_work(&chan->fr_poll_work); | ||
| 4525 | return; | ||
| 4526 | } | ||
| 4527 | |||
| 4528 | |||
| 4529 | /*============================================================ | ||
| 4530 | * fr_poll | ||
| 4531 | * | ||
| 4532 | * Rationale: | ||
| 4533 | * We cannot manipulate the routing tables, or | ||
| 4534 | * ip addresses withing the interrupt. Therefore | ||
| 4535 | * we must perform such actons outside an interrupt | ||
| 4536 | * at a later time. | ||
| 4537 | * | ||
| 4538 | * Description: | ||
| 4539 | * Frame relay polling routine, responsible for | ||
| 4540 | * shutting down interfaces upon disconnect | ||
| 4541 | * and adding/removing routes. | ||
| 4542 | * | ||
| 4543 | * Usage: | ||
| 4544 | * This function is executed for each frame relay | ||
| 4545 | * dlci/interface through a tq_schedule bottom half. | ||
| 4546 | * | ||
| 4547 | * trigger_fr_poll() function is used to kick | ||
| 4548 | * the fr_poll routine. | ||
| 4549 | */ | ||
| 4550 | |||
| 4551 | static void fr_poll(struct net_device *dev) | ||
| 4552 | { | ||
| 4553 | |||
| 4554 | fr_channel_t* chan; | ||
| 4555 | sdla_t *card; | ||
| 4556 | u8 check_gateway=0; | ||
| 4557 | |||
| 4558 | if (!dev || (chan = dev->priv) == NULL) | ||
| 4559 | return; | ||
| 4560 | |||
| 4561 | card = chan->card; | ||
| 4562 | |||
| 4563 | /* (Re)Configuraiton is in progress, stop what you are | ||
| 4564 | * doing and get out */ | ||
| 4565 | if (test_bit(PERI_CRIT,&card->wandev.critical)){ | ||
| 4566 | return; | ||
| 4567 | } | ||
| 4568 | |||
| 4569 | switch (chan->common.state){ | ||
| 4570 | |||
| 4571 | case WAN_DISCONNECTED: | ||
| 4572 | |||
| 4573 | if (test_bit(DYN_OPT_ON,&chan->interface_down) && | ||
| 4574 | !test_bit(DEV_DOWN, &chan->interface_down) && | ||
| 4575 | dev->flags&IFF_UP){ | ||
| 4576 | |||
| 4577 | printk(KERN_INFO "%s: Interface %s is Down.\n", | ||
| 4578 | card->devname,dev->name); | ||
| 4579 | change_dev_flags(dev,dev->flags&~IFF_UP); | ||
| 4580 | set_bit(DEV_DOWN, &chan->interface_down); | ||
| 4581 | chan->route_flag = NO_ROUTE; | ||
| 4582 | |||
| 4583 | }else{ | ||
| 4584 | if (chan->inarp != INARP_NONE) | ||
| 4585 | process_route(dev); | ||
| 4586 | } | ||
| 4587 | break; | ||
| 4588 | |||
| 4589 | case WAN_CONNECTED: | ||
| 4590 | |||
| 4591 | if (test_bit(DYN_OPT_ON,&chan->interface_down) && | ||
| 4592 | test_bit(DEV_DOWN, &chan->interface_down) && | ||
| 4593 | !(dev->flags&IFF_UP)){ | ||
| 4594 | |||
| 4595 | printk(KERN_INFO "%s: Interface %s is Up.\n", | ||
| 4596 | card->devname,dev->name); | ||
| 4597 | |||
| 4598 | change_dev_flags(dev,dev->flags|IFF_UP); | ||
| 4599 | clear_bit(DEV_DOWN, &chan->interface_down); | ||
| 4600 | check_gateway=1; | ||
| 4601 | } | ||
| 4602 | |||
| 4603 | if (chan->inarp != INARP_NONE){ | ||
| 4604 | process_route(dev); | ||
| 4605 | check_gateway=1; | ||
| 4606 | } | ||
| 4607 | |||
| 4608 | if (chan->gateway && check_gateway) | ||
| 4609 | add_gateway(card,dev); | ||
| 4610 | |||
| 4611 | break; | ||
| 4612 | |||
| 4613 | } | ||
| 4614 | |||
| 4615 | return; | ||
| 4616 | } | ||
| 4617 | |||
| 4618 | /*============================================================== | ||
| 4619 | * check_tx_status | ||
| 4620 | * | ||
| 4621 | * Rationale: | ||
| 4622 | * We cannot transmit from an interrupt while | ||
| 4623 | * the if_send is transmitting data. Therefore, | ||
| 4624 | * we must check whether the tx buffers are | ||
| 4625 | * begin used, before we transmit from an | ||
| 4626 | * interrupt. | ||
| 4627 | * | ||
| 4628 | * Description: | ||
| 4629 | * Checks whether it's safe to use the transmit | ||
| 4630 | * buffers. | ||
| 4631 | * | ||
| 4632 | * Usage: | ||
| 4633 | * ARP and UDP handling routines use this function | ||
| 4634 | * because, they need to transmit data during | ||
| 4635 | * an interrupt. | ||
| 4636 | */ | ||
| 4637 | |||
| 4638 | static int check_tx_status(sdla_t *card, struct net_device *dev) | ||
| 4639 | { | ||
| 4640 | |||
| 4641 | if (card->hw.type == SDLA_S514){ | ||
| 4642 | if (test_bit(SEND_CRIT, (void*)&card->wandev.critical) || | ||
| 4643 | test_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical)) { | ||
| 4644 | return 1; | ||
| 4645 | } | ||
| 4646 | } | ||
| 4647 | |||
| 4648 | if (netif_queue_stopped(dev) || (card->u.f.tx_interrupts_pending)) | ||
| 4649 | return 1; | ||
| 4650 | |||
| 4651 | return 0; | ||
| 4652 | } | ||
| 4653 | |||
| 4654 | /*=============================================================== | ||
| 4655 | * move_dev_to_next | ||
| 4656 | * | ||
| 4657 | * Description: | ||
| 4658 | * Move the dev pointer to the next location in the | ||
| 4659 | * link list. Check if we are at the end of the | ||
| 4660 | * list, if so start from the begining. | ||
| 4661 | * | ||
| 4662 | * Usage: | ||
| 4663 | * Timer interrupt uses this function to efficiently | ||
| 4664 | * step through the devices that need to send ARP data. | ||
| 4665 | * | ||
| 4666 | */ | ||
| 4667 | |||
| 4668 | struct net_device *move_dev_to_next(sdla_t *card, struct net_device *dev) | ||
| 4669 | { | ||
| 4670 | if (card->wandev.new_if_cnt != 1){ | ||
| 4671 | if (!*((struct net_device **)dev->priv)) | ||
| 4672 | return card->wandev.dev; | ||
| 4673 | else | ||
| 4674 | return *((struct net_device **)dev->priv); | ||
| 4675 | } | ||
| 4676 | return dev; | ||
| 4677 | } | ||
| 4678 | |||
| 4679 | /*============================================================== | ||
| 4680 | * trigger_config_fr | ||
| 4681 | * | ||
| 4682 | * Rationale: | ||
| 4683 | * All commands must be performed inside of a | ||
| 4684 | * interrupt. | ||
| 4685 | * | ||
| 4686 | * Description: | ||
| 4687 | * Kick the config_fr() routine throught the | ||
| 4688 | * timer interrupt. | ||
| 4689 | */ | ||
| 4690 | |||
| 4691 | |||
| 4692 | static void trigger_config_fr (sdla_t *card) | ||
| 4693 | { | ||
| 4694 | fr508_flags_t* flags = card->flags; | ||
| 4695 | |||
| 4696 | card->u.f.timer_int_enabled |= TMR_INT_ENABLED_CONFIG; | ||
| 4697 | flags->imask |= FR_INTR_TIMER; | ||
| 4698 | } | ||
| 4699 | |||
| 4700 | |||
| 4701 | /*============================================================== | ||
| 4702 | * config_fr | ||
| 4703 | * | ||
| 4704 | * Rationale: | ||
| 4705 | * All commands must be performed inside of a | ||
| 4706 | * interrupt. | ||
| 4707 | & | ||
| 4708 | * Description: | ||
| 4709 | * Configure a DLCI. This function is executed | ||
| 4710 | * by a timer_interrupt. The if_open() function | ||
| 4711 | * triggers it. | ||
| 4712 | * | ||
| 4713 | * Usage: | ||
| 4714 | * new_if() collects all data necessary to | ||
| 4715 | * configure the DLCI. It sets the chan->dlci_ready | ||
| 4716 | * bit. When the if_open() function is executed | ||
| 4717 | * it checks this bit, and if its set it triggers | ||
| 4718 | * the timer interrupt to execute the config_fr() | ||
| 4719 | * function. | ||
| 4720 | */ | ||
| 4721 | |||
| 4722 | static void config_fr (sdla_t *card) | ||
| 4723 | { | ||
| 4724 | struct net_device *dev; | ||
| 4725 | fr_channel_t *chan; | ||
| 4726 | |||
| 4727 | for (dev = card->wandev.dev; dev; | ||
| 4728 | dev = *((struct net_device **)dev->priv)) { | ||
| 4729 | |||
| 4730 | if ((chan=dev->priv) == NULL) | ||
| 4731 | continue; | ||
| 4732 | |||
| 4733 | if (!test_bit(0,&chan->config_dlci)) | ||
| 4734 | continue; | ||
| 4735 | |||
| 4736 | clear_bit(0,&chan->config_dlci); | ||
| 4737 | |||
| 4738 | /* If signalling is set to NO, then setup | ||
| 4739 | * DLCI addresses right away. Don't have to wait for | ||
| 4740 | * link to connect. | ||
| 4741 | */ | ||
| 4742 | if (card->wandev.signalling == WANOPT_NO){ | ||
| 4743 | printk(KERN_INFO "%s: Signalling set to NO: Mapping DLCI's\n", | ||
| 4744 | card->wandev.name); | ||
| 4745 | if (fr_init_dlci(card,chan)){ | ||
| 4746 | printk(KERN_INFO "%s: ERROR: Failed to configure DLCI %i !\n", | ||
| 4747 | card->devname, chan->dlci); | ||
| 4748 | return; | ||
| 4749 | } | ||
| 4750 | } | ||
| 4751 | |||
| 4752 | if (card->wandev.station == WANOPT_CPE) { | ||
| 4753 | |||
| 4754 | update_chan_state(dev); | ||
| 4755 | |||
| 4756 | /* CPE: issue full status enquiry */ | ||
| 4757 | fr_issue_isf(card, FR_ISF_FSE); | ||
| 4758 | |||
| 4759 | } else { | ||
| 4760 | /* FR switch: activate DLCI(s) */ | ||
| 4761 | |||
| 4762 | /* For Switch emulation we have to ADD and ACTIVATE | ||
| 4763 | * the DLCI(s) that were configured with the SET_DLCI_ | ||
| 4764 | * CONFIGURATION command. Add and Activate will fail if | ||
| 4765 | * DLCI specified is not included in the list. | ||
| 4766 | * | ||
| 4767 | * Also If_open is called once for each interface. But | ||
| 4768 | * it does not get in here for all the interface. So | ||
| 4769 | * we have to pass the entire list of DLCI(s) to add | ||
| 4770 | * activate routines. | ||
| 4771 | */ | ||
| 4772 | |||
| 4773 | if (!check_dlci_config (card, chan)){ | ||
| 4774 | fr_add_dlci(card, chan->dlci); | ||
| 4775 | fr_activate_dlci(card, chan->dlci); | ||
| 4776 | } | ||
| 4777 | } | ||
| 4778 | |||
| 4779 | card->u.f.dlci_to_dev_map[chan->dlci] = dev; | ||
| 4780 | } | ||
| 4781 | return; | ||
| 4782 | } | ||
| 4783 | |||
| 4784 | |||
| 4785 | /*============================================================== | ||
| 4786 | * config_fr | ||
| 4787 | * | ||
| 4788 | * Rationale: | ||
| 4789 | * All commands must be executed during an interrupt. | ||
| 4790 | * | ||
| 4791 | * Description: | ||
| 4792 | * Trigger uncofig_fr() function through | ||
| 4793 | * the timer interrupt. | ||
| 4794 | * | ||
| 4795 | */ | ||
| 4796 | |||
| 4797 | static void trigger_unconfig_fr(struct net_device *dev) | ||
| 4798 | { | ||
| 4799 | fr_channel_t *chan = dev->priv; | ||
| 4800 | volatile sdla_t *card = chan->card; | ||
| 4801 | unsigned long timeout; | ||
| 4802 | fr508_flags_t* flags = card->flags; | ||
| 4803 | int reset_critical=0; | ||
| 4804 | |||
| 4805 | if (test_bit(PERI_CRIT,(void*)&card->wandev.critical)){ | ||
| 4806 | clear_bit(PERI_CRIT,(void*)&card->wandev.critical); | ||
| 4807 | reset_critical=1; | ||
| 4808 | } | ||
| 4809 | |||
| 4810 | /* run unconfig_dlci() function | ||
| 4811 | * throught the timer interrupt */ | ||
| 4812 | set_bit(0,(void*)&chan->unconfig_dlci); | ||
| 4813 | card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UNCONFIG; | ||
| 4814 | flags->imask |= FR_INTR_TIMER; | ||
| 4815 | |||
| 4816 | /* Wait for the command to complete */ | ||
| 4817 | timeout = jiffies; | ||
| 4818 | for(;;) { | ||
| 4819 | |||
| 4820 | if(!(card->u.f.timer_int_enabled & TMR_INT_ENABLED_UNCONFIG)) | ||
| 4821 | break; | ||
| 4822 | |||
| 4823 | if (time_after(jiffies, timeout + 1 * HZ)){ | ||
| 4824 | card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UNCONFIG; | ||
| 4825 | printk(KERN_INFO "%s: Failed to delete DLCI %i\n", | ||
| 4826 | card->devname,chan->dlci); | ||
| 4827 | break; | ||
| 4828 | } | ||
| 4829 | } | ||
| 4830 | |||
| 4831 | if (reset_critical){ | ||
| 4832 | set_bit(PERI_CRIT,(void*)&card->wandev.critical); | ||
| 4833 | } | ||
| 4834 | } | ||
| 4835 | |||
| 4836 | /*============================================================== | ||
| 4837 | * unconfig_fr | ||
| 4838 | * | ||
| 4839 | * Rationale: | ||
| 4840 | * All commands must be executed during an interrupt. | ||
| 4841 | * | ||
| 4842 | * Description: | ||
| 4843 | * Remove the dlci from firmware. | ||
| 4844 | * This funciton is used in NODE shutdown. | ||
| 4845 | */ | ||
| 4846 | |||
| 4847 | static void unconfig_fr (sdla_t *card) | ||
| 4848 | { | ||
| 4849 | struct net_device *dev; | ||
| 4850 | fr_channel_t *chan; | ||
| 4851 | |||
| 4852 | for (dev = card->wandev.dev; dev; | ||
| 4853 | dev = *((struct net_device **)dev->priv)){ | ||
| 4854 | |||
| 4855 | if ((chan=dev->priv) == NULL) | ||
| 4856 | continue; | ||
| 4857 | |||
| 4858 | if (!test_bit(0,&chan->unconfig_dlci)) | ||
| 4859 | continue; | ||
| 4860 | |||
| 4861 | clear_bit(0,&chan->unconfig_dlci); | ||
| 4862 | |||
| 4863 | if (card->wandev.station == WANOPT_NODE){ | ||
| 4864 | printk(KERN_INFO "%s: Unconfiguring DLCI %i\n", | ||
| 4865 | card->devname,chan->dlci); | ||
| 4866 | fr_delete_dlci(card,chan->dlci); | ||
| 4867 | } | ||
| 4868 | card->u.f.dlci_to_dev_map[chan->dlci] = NULL; | ||
| 4869 | } | ||
| 4870 | } | ||
| 4871 | |||
| 4872 | static int setup_fr_header(struct sk_buff *skb, struct net_device* dev, | ||
| 4873 | char op_mode) | ||
| 4874 | { | ||
| 4875 | fr_channel_t *chan=dev->priv; | ||
| 4876 | |||
| 4877 | if (op_mode == WANPIPE) { | ||
| 4878 | chan->fr_header[0]=Q922_UI; | ||
| 4879 | |||
| 4880 | switch (htons(skb->protocol)){ | ||
| 4881 | case ETH_P_IP: | ||
| 4882 | chan->fr_header[1]=NLPID_IP; | ||
| 4883 | break; | ||
| 4884 | default: | ||
| 4885 | return -EINVAL; | ||
| 4886 | } | ||
| 4887 | |||
| 4888 | return 2; | ||
| 4889 | } | ||
| 4890 | |||
| 4891 | /* If we are in bridging mode, we must apply | ||
| 4892 | * an Ethernet header | ||
| 4893 | */ | ||
| 4894 | if (op_mode == BRIDGE || op_mode == BRIDGE_NODE) { | ||
| 4895 | /* Encapsulate the packet as a bridged Ethernet frame. */ | ||
| 4896 | #ifdef DEBUG | ||
| 4897 | printk(KERN_INFO "%s: encapsulating skb for frame relay\n", | ||
| 4898 | dev->name); | ||
| 4899 | #endif | ||
| 4900 | chan->fr_header[0] = 0x03; | ||
| 4901 | chan->fr_header[1] = 0x00; | ||
| 4902 | chan->fr_header[2] = 0x80; | ||
| 4903 | chan->fr_header[3] = 0x00; | ||
| 4904 | chan->fr_header[4] = 0x80; | ||
| 4905 | chan->fr_header[5] = 0xC2; | ||
| 4906 | chan->fr_header[6] = 0x00; | ||
| 4907 | chan->fr_header[7] = 0x07; | ||
| 4908 | |||
| 4909 | /* Yuck. */ | ||
| 4910 | skb->protocol = ETH_P_802_3; | ||
| 4911 | return 8; | ||
| 4912 | } | ||
| 4913 | |||
| 4914 | return 0; | ||
| 4915 | } | ||
| 4916 | |||
| 4917 | |||
| 4918 | static int check_dlci_config (sdla_t *card, fr_channel_t *chan) | ||
| 4919 | { | ||
| 4920 | fr_mbox_t* mbox = card->mbox; | ||
| 4921 | int err=0; | ||
| 4922 | fr_conf_t *conf=NULL; | ||
| 4923 | unsigned short dlci_num = chan->dlci; | ||
| 4924 | int dlci_offset=0; | ||
| 4925 | struct net_device *dev = NULL; | ||
| 4926 | |||
| 4927 | mbox->cmd.command = FR_READ_CONFIG; | ||
| 4928 | mbox->cmd.length = 0; | ||
| 4929 | mbox->cmd.dlci = dlci_num; | ||
| 4930 | |||
| 4931 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 4932 | |||
| 4933 | if (err == CMD_OK){ | ||
| 4934 | return 0; | ||
| 4935 | } | ||
| 4936 | |||
| 4937 | for (dev = card->wandev.dev; dev; | ||
| 4938 | dev=*((struct net_device **)dev->priv)) | ||
| 4939 | set_chan_state(dev,WAN_DISCONNECTED); | ||
| 4940 | |||
| 4941 | printk(KERN_INFO "DLCI %i Not configured, configuring\n",dlci_num); | ||
| 4942 | |||
| 4943 | mbox->cmd.command = FR_COMM_DISABLE; | ||
| 4944 | mbox->cmd.length = 0; | ||
| 4945 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 4946 | if (err != CMD_OK){ | ||
| 4947 | fr_event(card, err, mbox); | ||
| 4948 | return 2; | ||
| 4949 | } | ||
| 4950 | |||
| 4951 | printk(KERN_INFO "Disabled Communications \n"); | ||
| 4952 | |||
| 4953 | mbox->cmd.command = FR_READ_CONFIG; | ||
| 4954 | mbox->cmd.length = 0; | ||
| 4955 | mbox->cmd.dlci = 0; | ||
| 4956 | |||
| 4957 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 4958 | |||
| 4959 | if (err != CMD_OK){ | ||
| 4960 | fr_event(card, err, mbox); | ||
| 4961 | return 2; | ||
| 4962 | } | ||
| 4963 | |||
| 4964 | conf = (fr_conf_t *)mbox->data; | ||
| 4965 | |||
| 4966 | dlci_offset=0; | ||
| 4967 | for (dev = card->wandev.dev; dev; | ||
| 4968 | dev = *((struct net_device **)dev->priv)) { | ||
| 4969 | fr_channel_t *chan_tmp = dev->priv; | ||
| 4970 | conf->dlci[dlci_offset] = chan_tmp->dlci; | ||
| 4971 | dlci_offset++; | ||
| 4972 | } | ||
| 4973 | |||
| 4974 | printk(KERN_INFO "Got Fr configuration Buffer Length is %x Dlci %i Dlci Off %i\n", | ||
| 4975 | mbox->cmd.length, | ||
| 4976 | mbox->cmd.length > 0x20 ? conf->dlci[0] : -1, | ||
| 4977 | dlci_offset ); | ||
| 4978 | |||
| 4979 | mbox->cmd.length = 0x20 + dlci_offset*2; | ||
| 4980 | |||
| 4981 | mbox->cmd.command = FR_SET_CONFIG; | ||
| 4982 | mbox->cmd.dlci = 0; | ||
| 4983 | |||
| 4984 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 4985 | |||
| 4986 | if (err != CMD_OK){ | ||
| 4987 | fr_event(card, err, mbox); | ||
| 4988 | return 2; | ||
| 4989 | } | ||
| 4990 | |||
| 4991 | initialize_rx_tx_buffers (card); | ||
| 4992 | |||
| 4993 | |||
| 4994 | printk(KERN_INFO "Configuraiton Succeded for new DLCI %i\n",dlci_num); | ||
| 4995 | |||
| 4996 | if (fr_comm_enable (card)){ | ||
| 4997 | return 2; | ||
| 4998 | } | ||
| 4999 | |||
| 5000 | printk(KERN_INFO "Enabling Communications \n"); | ||
| 5001 | |||
| 5002 | for (dev = card->wandev.dev; dev; | ||
| 5003 | dev = *((struct net_device **)dev->priv)) { | ||
| 5004 | fr_channel_t *chan_tmp = dev->priv; | ||
| 5005 | fr_init_dlci(card,chan_tmp); | ||
| 5006 | fr_add_dlci(card, chan_tmp->dlci); | ||
| 5007 | fr_activate_dlci(card, chan_tmp->dlci); | ||
| 5008 | } | ||
| 5009 | |||
| 5010 | printk(KERN_INFO "END OF CONFIGURAITON %i\n",dlci_num); | ||
| 5011 | |||
| 5012 | return 1; | ||
| 5013 | } | ||
| 5014 | |||
| 5015 | static void initialize_rx_tx_buffers (sdla_t *card) | ||
| 5016 | { | ||
| 5017 | fr_buf_info_t* buf_info; | ||
| 5018 | |||
| 5019 | if (card->hw.type == SDLA_S514) { | ||
| 5020 | |||
| 5021 | buf_info = (void*)(card->hw.dpmbase + FR_MB_VECTOR + | ||
| 5022 | FR508_RXBC_OFFS); | ||
| 5023 | |||
| 5024 | card->rxmb = (void*)(buf_info->rse_next + card->hw.dpmbase); | ||
| 5025 | |||
| 5026 | card->u.f.rxmb_base = | ||
| 5027 | (void*)(buf_info->rse_base + card->hw.dpmbase); | ||
| 5028 | |||
| 5029 | card->u.f.rxmb_last = | ||
| 5030 | (void*)(buf_info->rse_base + | ||
| 5031 | (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) + | ||
| 5032 | card->hw.dpmbase); | ||
| 5033 | }else{ | ||
| 5034 | buf_info = (void*)(card->hw.dpmbase + FR508_RXBC_OFFS); | ||
| 5035 | |||
| 5036 | card->rxmb = (void*)(buf_info->rse_next - | ||
| 5037 | FR_MB_VECTOR + card->hw.dpmbase); | ||
| 5038 | |||
| 5039 | card->u.f.rxmb_base = | ||
| 5040 | (void*)(buf_info->rse_base - | ||
| 5041 | FR_MB_VECTOR + card->hw.dpmbase); | ||
| 5042 | |||
| 5043 | card->u.f.rxmb_last = | ||
| 5044 | (void*)(buf_info->rse_base + | ||
| 5045 | (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) - | ||
| 5046 | FR_MB_VECTOR + card->hw.dpmbase); | ||
| 5047 | } | ||
| 5048 | |||
| 5049 | card->u.f.rx_base = buf_info->buf_base; | ||
| 5050 | card->u.f.rx_top = buf_info->buf_top; | ||
| 5051 | |||
| 5052 | card->u.f.tx_interrupts_pending = 0; | ||
| 5053 | |||
| 5054 | return; | ||
| 5055 | } | ||
| 5056 | |||
| 5057 | |||
| 5058 | |||
| 5059 | MODULE_LICENSE("GPL"); | ||
| 5060 | |||
| 5061 | /****** End *****************************************************************/ | ||
diff --git a/drivers/net/wan/sdla_ft1.c b/drivers/net/wan/sdla_ft1.c deleted file mode 100644 index 9d6528a50f7b..000000000000 --- a/drivers/net/wan/sdla_ft1.c +++ /dev/null | |||
| @@ -1,345 +0,0 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * sdla_chdlc.c WANPIPE(tm) Multiprotocol WAN Link Driver. Cisco HDLC module. | ||
| 3 | * | ||
| 4 | * Authors: Nenad Corbic <ncorbic@sangoma.com> | ||
| 5 | * Gideon Hack | ||
| 6 | * | ||
| 7 | * Copyright: (c) 1995-1999 Sangoma Technologies Inc. | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or | ||
| 10 | * modify it under the terms of the GNU General Public License | ||
| 11 | * as published by the Free Software Foundation; either version | ||
| 12 | * 2 of the License, or (at your option) any later version. | ||
| 13 | * ============================================================================ | ||
| 14 | * Sep 30, 1999 Nenad Corbic Fixed dynamic IP and route setup. | ||
| 15 | * Sep 23, 1999 Nenad Corbic Added SMP support, fixed tracing | ||
| 16 | * Sep 13, 1999 Nenad Corbic Split up Port 0 and 1 into separate devices. | ||
| 17 | * Jun 02, 1999 Gideon Hack Added support for the S514 adapter. | ||
| 18 | * Oct 30, 1998 Jaspreet Singh Added Support for CHDLC API (HDLC STREAMING). | ||
| 19 | * Oct 28, 1998 Jaspreet Singh Added Support for Dual Port CHDLC. | ||
| 20 | * Aug 07, 1998 David Fong Initial version. | ||
| 21 | *****************************************************************************/ | ||
| 22 | |||
| 23 | #include <linux/module.h> | ||
| 24 | #include <linux/kernel.h> /* printk(), and other useful stuff */ | ||
| 25 | #include <linux/stddef.h> /* offsetof(), etc. */ | ||
| 26 | #include <linux/errno.h> /* return codes */ | ||
| 27 | #include <linux/string.h> /* inline memset(), etc. */ | ||
| 28 | #include <linux/slab.h> /* kmalloc(), kfree() */ | ||
| 29 | #include <linux/wanrouter.h> /* WAN router definitions */ | ||
| 30 | #include <linux/wanpipe.h> /* WANPIPE common user API definitions */ | ||
| 31 | #include <linux/if_arp.h> /* ARPHRD_* defines */ | ||
| 32 | #include <linux/jiffies.h> /* time_after() macro */ | ||
| 33 | |||
| 34 | #include <linux/inetdevice.h> | ||
| 35 | #include <asm/uaccess.h> | ||
| 36 | |||
| 37 | #include <linux/in.h> /* sockaddr_in */ | ||
| 38 | #include <linux/inet.h> | ||
| 39 | #include <linux/if.h> | ||
| 40 | #include <asm/byteorder.h> /* htons(), etc. */ | ||
| 41 | #include <linux/sdlapci.h> | ||
| 42 | #include <asm/io.h> | ||
| 43 | |||
| 44 | #include <linux/sdla_chdlc.h> /* CHDLC firmware API definitions */ | ||
| 45 | |||
| 46 | /****** Defines & Macros ****************************************************/ | ||
| 47 | |||
| 48 | /* reasons for enabling the timer interrupt on the adapter */ | ||
| 49 | #define TMR_INT_ENABLED_UDP 0x0001 | ||
| 50 | #define TMR_INT_ENABLED_UPDATE 0x0002 | ||
| 51 | |||
| 52 | #define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ | ||
| 53 | #define CHDLC_HDR_LEN 1 | ||
| 54 | |||
| 55 | #define IFF_POINTTOPOINT 0x10 | ||
| 56 | |||
| 57 | #define WANPIPE 0x00 | ||
| 58 | #define API 0x01 | ||
| 59 | #define CHDLC_API 0x01 | ||
| 60 | |||
| 61 | #define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) | ||
| 62 | |||
| 63 | |||
| 64 | /******Data Structures*****************************************************/ | ||
| 65 | |||
| 66 | /* This structure is placed in the private data area of the device structure. | ||
| 67 | * The card structure used to occupy the private area but now the following | ||
| 68 | * structure will incorporate the card structure along with CHDLC specific data | ||
| 69 | */ | ||
| 70 | |||
| 71 | typedef struct chdlc_private_area | ||
| 72 | { | ||
| 73 | struct net_device *slave; | ||
| 74 | sdla_t *card; | ||
| 75 | int TracingEnabled; /* For enabling Tracing */ | ||
| 76 | unsigned long curr_trace_addr; /* Used for Tracing */ | ||
| 77 | unsigned long start_trace_addr; | ||
| 78 | unsigned long end_trace_addr; | ||
| 79 | unsigned long base_addr_trace_buffer; | ||
| 80 | unsigned long end_addr_trace_buffer; | ||
| 81 | unsigned short number_trace_elements; | ||
| 82 | unsigned available_buffer_space; | ||
| 83 | unsigned long router_start_time; | ||
| 84 | unsigned char route_status; | ||
| 85 | unsigned char route_removed; | ||
| 86 | unsigned long tick_counter; /* For 5s timeout counter */ | ||
| 87 | unsigned long router_up_time; | ||
| 88 | u32 IP_address; /* IP addressing */ | ||
| 89 | u32 IP_netmask; | ||
| 90 | unsigned char mc; /* Mulitcast support on/off */ | ||
| 91 | unsigned short udp_pkt_lgth; /* udp packet processing */ | ||
| 92 | char udp_pkt_src; | ||
| 93 | char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; | ||
| 94 | unsigned short timer_int_enabled; | ||
| 95 | char update_comms_stats; /* updating comms stats */ | ||
| 96 | //FIXME: add driver stats as per frame relay! | ||
| 97 | |||
| 98 | } chdlc_private_area_t; | ||
| 99 | |||
| 100 | /* Route Status options */ | ||
| 101 | #define NO_ROUTE 0x00 | ||
| 102 | #define ADD_ROUTE 0x01 | ||
| 103 | #define ROUTE_ADDED 0x02 | ||
| 104 | #define REMOVE_ROUTE 0x03 | ||
| 105 | |||
| 106 | |||
| 107 | /****** Function Prototypes *************************************************/ | ||
| 108 | /* WAN link driver entry points. These are called by the WAN router module. */ | ||
| 109 | static int wpft1_exec (struct sdla *card, void *u_cmd, void *u_data); | ||
| 110 | static int chdlc_read_version (sdla_t* card, char* str); | ||
| 111 | static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb); | ||
| 112 | |||
| 113 | /****** Public Functions ****************************************************/ | ||
| 114 | |||
| 115 | /*============================================================================ | ||
| 116 | * Cisco HDLC protocol initialization routine. | ||
| 117 | * | ||
| 118 | * This routine is called by the main WANPIPE module during setup. At this | ||
| 119 | * point adapter is completely initialized and firmware is running. | ||
| 120 | * o read firmware version (to make sure it's alive) | ||
| 121 | * o configure adapter | ||
| 122 | * o initialize protocol-specific fields of the adapter data space. | ||
| 123 | * | ||
| 124 | * Return: 0 o.k. | ||
| 125 | * < 0 failure. | ||
| 126 | */ | ||
| 127 | int wpft1_init (sdla_t* card, wandev_conf_t* conf) | ||
| 128 | { | ||
| 129 | unsigned char port_num; | ||
| 130 | int err; | ||
| 131 | |||
| 132 | union | ||
| 133 | { | ||
| 134 | char str[80]; | ||
| 135 | } u; | ||
| 136 | volatile CHDLC_MAILBOX_STRUCT* mb; | ||
| 137 | CHDLC_MAILBOX_STRUCT* mb1; | ||
| 138 | unsigned long timeout; | ||
| 139 | |||
| 140 | /* Verify configuration ID */ | ||
| 141 | if (conf->config_id != WANCONFIG_CHDLC) { | ||
| 142 | printk(KERN_INFO "%s: invalid configuration ID %u!\n", | ||
| 143 | card->devname, conf->config_id); | ||
| 144 | return -EINVAL; | ||
| 145 | } | ||
| 146 | |||
| 147 | /* Use primary port */ | ||
| 148 | card->u.c.comm_port = 0; | ||
| 149 | |||
| 150 | |||
| 151 | /* Initialize protocol-specific fields */ | ||
| 152 | if(card->hw.type != SDLA_S514){ | ||
| 153 | card->mbox = (void *) card->hw.dpmbase; | ||
| 154 | }else{ | ||
| 155 | card->mbox = (void *) card->hw.dpmbase + PRI_BASE_ADDR_MB_STRUCT; | ||
| 156 | } | ||
| 157 | |||
| 158 | mb = mb1 = card->mbox; | ||
| 159 | |||
| 160 | if (!card->configured){ | ||
| 161 | |||
| 162 | /* The board will place an 'I' in the return code to indicate that it is | ||
| 163 | ready to accept commands. We expect this to be completed in less | ||
| 164 | than 1 second. */ | ||
| 165 | |||
| 166 | timeout = jiffies; | ||
| 167 | while (mb->return_code != 'I') /* Wait 1s for board to initialize */ | ||
| 168 | if (time_after(jiffies, timeout + 1*HZ)) break; | ||
| 169 | |||
| 170 | if (mb->return_code != 'I') { | ||
| 171 | printk(KERN_INFO | ||
| 172 | "%s: Initialization not completed by adapter\n", | ||
| 173 | card->devname); | ||
| 174 | printk(KERN_INFO "Please contact Sangoma representative.\n"); | ||
| 175 | return -EIO; | ||
| 176 | } | ||
| 177 | } | ||
| 178 | |||
| 179 | /* Read firmware version. Note that when adapter initializes, it | ||
| 180 | * clears the mailbox, so it may appear that the first command was | ||
| 181 | * executed successfully when in fact it was merely erased. To work | ||
| 182 | * around this, we execute the first command twice. | ||
| 183 | */ | ||
| 184 | |||
| 185 | if (chdlc_read_version(card, u.str)) | ||
| 186 | return -EIO; | ||
| 187 | |||
| 188 | printk(KERN_INFO "%s: Running FT1 Configuration firmware v%s\n", | ||
| 189 | card->devname, u.str); | ||
| 190 | |||
| 191 | card->isr = NULL; | ||
| 192 | card->poll = NULL; | ||
| 193 | card->exec = &wpft1_exec; | ||
| 194 | card->wandev.update = NULL; | ||
| 195 | card->wandev.new_if = NULL; | ||
| 196 | card->wandev.del_if = NULL; | ||
| 197 | card->wandev.state = WAN_DUALPORT; | ||
| 198 | card->wandev.udp_port = conf->udp_port; | ||
| 199 | |||
| 200 | card->wandev.new_if_cnt = 0; | ||
| 201 | |||
| 202 | /* This is for the ports link state */ | ||
| 203 | card->u.c.state = WAN_DISCONNECTED; | ||
| 204 | |||
| 205 | /* reset the number of times the 'update()' proc has been called */ | ||
| 206 | card->u.c.update_call_count = 0; | ||
| 207 | |||
| 208 | card->wandev.ttl = 0x7F; | ||
| 209 | card->wandev.interface = 0; | ||
| 210 | |||
| 211 | card->wandev.clocking = 0; | ||
| 212 | |||
| 213 | port_num = card->u.c.comm_port; | ||
| 214 | |||
| 215 | /* Setup Port Bps */ | ||
| 216 | |||
| 217 | card->wandev.bps = 0; | ||
| 218 | |||
| 219 | card->wandev.mtu = MIN_LGTH_CHDLC_DATA_CFG; | ||
| 220 | |||
| 221 | /* Set up the interrupt status area */ | ||
| 222 | /* Read the CHDLC Configuration and obtain: | ||
| 223 | * Ptr to shared memory infor struct | ||
| 224 | * Use this pointer to calculate the value of card->u.c.flags ! | ||
| 225 | */ | ||
| 226 | mb1->buffer_length = 0; | ||
| 227 | mb1->command = READ_CHDLC_CONFIGURATION; | ||
| 228 | err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT; | ||
| 229 | if(err != COMMAND_OK) { | ||
| 230 | chdlc_error(card, err, mb1); | ||
| 231 | return -EIO; | ||
| 232 | } | ||
| 233 | |||
| 234 | if(card->hw.type == SDLA_S514){ | ||
| 235 | card->u.c.flags = (void *)(card->hw.dpmbase + | ||
| 236 | (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> | ||
| 237 | ptr_shared_mem_info_struct)); | ||
| 238 | }else{ | ||
| 239 | card->u.c.flags = (void *)(card->hw.dpmbase + | ||
| 240 | (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> | ||
| 241 | ptr_shared_mem_info_struct % SDLA_WINDOWSIZE)); | ||
| 242 | } | ||
| 243 | |||
| 244 | card->wandev.state = WAN_FT1_READY; | ||
| 245 | printk(KERN_INFO "%s: FT1 Config Ready !\n",card->devname); | ||
| 246 | |||
| 247 | return 0; | ||
| 248 | } | ||
| 249 | |||
| 250 | static int wpft1_exec(sdla_t *card, void *u_cmd, void *u_data) | ||
| 251 | { | ||
| 252 | CHDLC_MAILBOX_STRUCT* mbox = card->mbox; | ||
| 253 | int len; | ||
| 254 | |||
| 255 | if (copy_from_user((void*)&mbox->command, u_cmd, sizeof(ft1_exec_cmd_t))){ | ||
| 256 | return -EFAULT; | ||
| 257 | } | ||
| 258 | |||
| 259 | len = mbox->buffer_length; | ||
| 260 | |||
| 261 | if (len) { | ||
| 262 | if( copy_from_user((void*)&mbox->data, u_data, len)){ | ||
| 263 | return -EFAULT; | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | /* execute command */ | ||
| 268 | if (!sdla_exec(mbox)){ | ||
| 269 | return -EIO; | ||
| 270 | } | ||
| 271 | |||
| 272 | /* return result */ | ||
| 273 | if( copy_to_user(u_cmd, (void*)&mbox->command, sizeof(ft1_exec_cmd_t))){ | ||
| 274 | return -EFAULT; | ||
| 275 | } | ||
| 276 | |||
| 277 | len = mbox->buffer_length; | ||
| 278 | |||
| 279 | if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len)){ | ||
| 280 | return -EFAULT; | ||
| 281 | } | ||
| 282 | |||
| 283 | return 0; | ||
| 284 | |||
| 285 | } | ||
| 286 | |||
| 287 | /*============================================================================ | ||
| 288 | * Read firmware code version. | ||
| 289 | * Put code version as ASCII string in str. | ||
| 290 | */ | ||
| 291 | static int chdlc_read_version (sdla_t* card, char* str) | ||
| 292 | { | ||
| 293 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
| 294 | int len; | ||
| 295 | char err; | ||
| 296 | mb->buffer_length = 0; | ||
| 297 | mb->command = READ_CHDLC_CODE_VERSION; | ||
| 298 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 299 | |||
| 300 | if(err != COMMAND_OK) { | ||
| 301 | chdlc_error(card,err,mb); | ||
| 302 | } | ||
| 303 | else if (str) { /* is not null */ | ||
| 304 | len = mb->buffer_length; | ||
| 305 | memcpy(str, mb->data, len); | ||
| 306 | str[len] = '\0'; | ||
| 307 | } | ||
| 308 | return (err); | ||
| 309 | } | ||
| 310 | |||
| 311 | /*============================================================================ | ||
| 312 | * Firmware error handler. | ||
| 313 | * This routine is called whenever firmware command returns non-zero | ||
| 314 | * return code. | ||
| 315 | * | ||
| 316 | * Return zero if previous command has to be cancelled. | ||
| 317 | */ | ||
| 318 | static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb) | ||
| 319 | { | ||
| 320 | unsigned cmd = mb->command; | ||
| 321 | |||
| 322 | switch (err) { | ||
| 323 | |||
| 324 | case CMD_TIMEOUT: | ||
| 325 | printk(KERN_ERR "%s: command 0x%02X timed out!\n", | ||
| 326 | card->devname, cmd); | ||
| 327 | break; | ||
| 328 | |||
| 329 | case S514_BOTH_PORTS_SAME_CLK_MODE: | ||
| 330 | if(cmd == SET_CHDLC_CONFIGURATION) { | ||
| 331 | printk(KERN_INFO | ||
| 332 | "%s: Configure both ports for the same clock source\n", | ||
| 333 | card->devname); | ||
| 334 | break; | ||
| 335 | } | ||
| 336 | |||
| 337 | default: | ||
| 338 | printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", | ||
| 339 | card->devname, cmd, err); | ||
| 340 | } | ||
| 341 | |||
| 342 | return 0; | ||
| 343 | } | ||
| 344 | |||
| 345 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/net/wan/sdla_ppp.c b/drivers/net/wan/sdla_ppp.c deleted file mode 100644 index a4b489cccbbf..000000000000 --- a/drivers/net/wan/sdla_ppp.c +++ /dev/null | |||
| @@ -1,3430 +0,0 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * sdla_ppp.c WANPIPE(tm) Multiprotocol WAN Link Driver. PPP module. | ||
| 3 | * | ||
| 4 | * Author: Nenad Corbic <ncorbic@sangoma.com> | ||
| 5 | * | ||
| 6 | * Copyright: (c) 1995-2001 Sangoma Technologies Inc. | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or | ||
| 9 | * modify it under the terms of the GNU General Public License | ||
| 10 | * as published by the Free Software Foundation; either version | ||
| 11 | * 2 of the License, or (at your option) any later version. | ||
| 12 | * ============================================================================ | ||
| 13 | * Feb 28, 2001 Nenad Corbic o Updated if_tx_timeout() routine for | ||
| 14 | * 2.4.X kernels. | ||
| 15 | * Nov 29, 2000 Nenad Corbic o Added the 2.4.x kernel support: | ||
| 16 | * get_ip_address() function has moved | ||
| 17 | * into the ppp_poll() routine. It cannot | ||
| 18 | * be called from an interrupt. | ||
| 19 | * Nov 07, 2000 Nenad Corbic o Added security features for UDP debugging: | ||
| 20 | * Deny all and specify allowed requests. | ||
| 21 | * May 02, 2000 Nenad Corbic o Added the dynamic interface shutdown | ||
| 22 | * option. When the link goes down, the | ||
| 23 | * network interface IFF_UP flag is reset. | ||
| 24 | * Mar 06, 2000 Nenad Corbic o Bug Fix: corrupted mbox recovery. | ||
| 25 | * Feb 25, 2000 Nenad Corbic o Fixed the FT1 UDP debugger problem. | ||
| 26 | * Feb 09, 2000 Nenad Coribc o Shutdown bug fix. update() was called | ||
| 27 | * with NULL dev pointer: no check. | ||
| 28 | * Jan 24, 2000 Nenad Corbic o Disabled use of CMD complete inter. | ||
| 29 | * Dev 15, 1999 Nenad Corbic o Fixed up header files for 2.0.X kernels | ||
| 30 | * Oct 25, 1999 Nenad Corbic o Support for 2.0.X kernels | ||
| 31 | * Moved dynamic route processing into | ||
| 32 | * a polling routine. | ||
| 33 | * Oct 07, 1999 Nenad Corbic o Support for S514 PCI card. | ||
| 34 | * Gideon Hack o UPD and Updates executed using timer interrupt | ||
| 35 | * Sep 10, 1999 Nenad Corbic o Fixed up the /proc statistics | ||
| 36 | * Jul 20, 1999 Nenad Corbic o Remove the polling routines and use | ||
| 37 | * interrupts instead. | ||
| 38 | * Sep 17, 1998 Jaspreet Singh o Updates for 2.2.X Kernels. | ||
| 39 | * Aug 13, 1998 Jaspreet Singh o Improved Line Tracing. | ||
| 40 | * Jun 22, 1998 David Fong o Added remote IP address assignment | ||
| 41 | * Mar 15, 1998 Alan Cox o 2.1.8x basic port. | ||
| 42 | * Apr 16, 1998 Jaspreet Singh o using htons() for the IPX protocol. | ||
| 43 | * Dec 09, 1997 Jaspreet Singh o Added PAP and CHAP. | ||
| 44 | * o Implemented new routines like | ||
| 45 | * ppp_set_inbnd_auth(), ppp_set_outbnd_auth(), | ||
| 46 | * tokenize() and strstrip(). | ||
| 47 | * Nov 27, 1997 Jaspreet Singh o Added protection against enabling of irqs | ||
| 48 | * while they have been disabled. | ||
| 49 | * Nov 24, 1997 Jaspreet Singh o Fixed another RACE condition caused by | ||
| 50 | * disabling and enabling of irqs. | ||
| 51 | * o Added new counters for stats on disable/enable | ||
| 52 | * IRQs. | ||
| 53 | * Nov 10, 1997 Jaspreet Singh o Initialized 'skb->mac.raw' to 'skb->data' | ||
| 54 | * before every netif_rx(). | ||
| 55 | * o Free up the device structure in del_if(). | ||
| 56 | * Nov 07, 1997 Jaspreet Singh o Changed the delay to zero for Line tracing | ||
| 57 | * command. | ||
| 58 | * Oct 20, 1997 Jaspreet Singh o Added hooks in for Router UP time. | ||
| 59 | * Oct 16, 1997 Jaspreet Singh o The critical flag is used to maintain flow | ||
| 60 | * control by avoiding RACE conditions. The | ||
| 61 | * cli() and restore_flags() are taken out. | ||
| 62 | * A new structure, "ppp_private_area", is added | ||
| 63 | * to provide Driver Statistics. | ||
| 64 | * Jul 21, 1997 Jaspreet Singh o Protected calls to sdla_peek() by adding | ||
| 65 | * save_flags(), cli() and restore_flags(). | ||
| 66 | * Jul 07, 1997 Jaspreet Singh o Added configurable TTL for UDP packets | ||
| 67 | * o Added ability to discard mulitcast and | ||
| 68 | * broacast source addressed packets. | ||
| 69 | * Jun 27, 1997 Jaspreet Singh o Added FT1 monitor capabilities | ||
| 70 | * New case (0x25) statement in if_send routine. | ||
| 71 | * Added a global variable rCount to keep track | ||
| 72 | * of FT1 status enabled on the board. | ||
| 73 | * May 22, 1997 Jaspreet Singh o Added change in the PPP_SET_CONFIG command for | ||
| 74 | * 508 card to reflect changes in the new | ||
| 75 | * ppp508.sfm for supporting:continous transmission | ||
| 76 | * of Configure-Request packets without receiving a | ||
| 77 | * reply | ||
| 78 | * OR-ed 0x300 to conf_flags | ||
| 79 | * o Changed connect_tmout from 900 to 0 | ||
| 80 | * May 21, 1997 Jaspreet Singh o Fixed UDP Management for multiple boards | ||
| 81 | * Apr 25, 1997 Farhan Thawar o added UDP Management stuff | ||
| 82 | * Mar 11, 1997 Farhan Thawar Version 3.1.1 | ||
| 83 | * o fixed (+1) bug in rx_intr() | ||
| 84 | * o changed if_send() to return 0 if | ||
| 85 | * wandev.critical() is true | ||
| 86 | * o free socket buffer in if_send() if | ||
| 87 | * returning 0 | ||
| 88 | * Jan 15, 1997 Gene Kozin Version 3.1.0 | ||
| 89 | * o implemented exec() entry point | ||
| 90 | * Jan 06, 1997 Gene Kozin Initial version. | ||
| 91 | *****************************************************************************/ | ||
| 92 | |||
| 93 | #include <linux/module.h> | ||
| 94 | #include <linux/kernel.h> /* printk(), and other useful stuff */ | ||
| 95 | #include <linux/stddef.h> /* offsetof(), etc. */ | ||
| 96 | #include <linux/errno.h> /* return codes */ | ||
| 97 | #include <linux/string.h> /* inline memset(), etc. */ | ||
| 98 | #include <linux/slab.h> /* kmalloc(), kfree() */ | ||
| 99 | #include <linux/wanrouter.h> /* WAN router definitions */ | ||
| 100 | #include <linux/wanpipe.h> /* WANPIPE common user API definitions */ | ||
| 101 | #include <linux/if_arp.h> /* ARPHRD_* defines */ | ||
| 102 | #include <asm/byteorder.h> /* htons(), etc. */ | ||
| 103 | #include <linux/in.h> /* sockaddr_in */ | ||
| 104 | #include <linux/jiffies.h> /* time_after() macro */ | ||
| 105 | |||
| 106 | |||
| 107 | #include <asm/uaccess.h> | ||
| 108 | #include <linux/inetdevice.h> | ||
| 109 | #include <linux/netdevice.h> | ||
| 110 | |||
| 111 | #include <linux/if.h> | ||
| 112 | #include <linux/sdla_ppp.h> /* PPP firmware API definitions */ | ||
| 113 | #include <linux/sdlasfm.h> /* S514 Type Definition */ | ||
| 114 | /****** Defines & Macros ****************************************************/ | ||
| 115 | |||
| 116 | #define PPP_DFLT_MTU 1500 /* default MTU */ | ||
| 117 | #define PPP_MAX_MTU 4000 /* maximum MTU */ | ||
| 118 | #define PPP_HDR_LEN 1 | ||
| 119 | |||
| 120 | #define MAX_IP_ERRORS 100 | ||
| 121 | |||
| 122 | #define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ | ||
| 123 | #define HOLD_DOWN_TIME (5*HZ) /* link hold down time : Changed from 30 to 5 */ | ||
| 124 | |||
| 125 | /* For handle_IPXWAN() */ | ||
| 126 | #define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) | ||
| 127 | |||
| 128 | /* Macro for enabling/disabling debugging comments */ | ||
| 129 | //#define NEX_DEBUG | ||
| 130 | #ifdef NEX_DEBUG | ||
| 131 | #define NEX_PRINTK(format, a...) printk(format, ## a) | ||
| 132 | #else | ||
| 133 | #define NEX_PRINTK(format, a...) | ||
| 134 | #endif /* NEX_DEBUG */ | ||
| 135 | |||
| 136 | #define DCD(a) ( a & 0x08 ? "HIGH" : "LOW" ) | ||
| 137 | #define CTS(a) ( a & 0x20 ? "HIGH" : "LOW" ) | ||
| 138 | #define LCP(a) ( a == 0x09 ? "OPEN" : "CLOSED" ) | ||
| 139 | #define IP(a) ( a == 0x09 ? "ENABLED" : "DISABLED" ) | ||
| 140 | |||
| 141 | #define TMR_INT_ENABLED_UPDATE 0x01 | ||
| 142 | #define TMR_INT_ENABLED_PPP_EVENT 0x02 | ||
| 143 | #define TMR_INT_ENABLED_UDP 0x04 | ||
| 144 | #define TMR_INT_ENABLED_CONFIG 0x20 | ||
| 145 | |||
| 146 | /* Set Configuraton Command Definitions */ | ||
| 147 | #define PERCENT_TX_BUFF 60 | ||
| 148 | #define TIME_BETWEEN_CONF_REQ 30 | ||
| 149 | #define TIME_BETWEEN_PAP_CHAP_REQ 30 | ||
| 150 | #define WAIT_PAP_CHAP_WITHOUT_REPLY 300 | ||
| 151 | #define WAIT_AFTER_DCD_CTS_LOW 5 | ||
| 152 | #define TIME_DCD_CTS_LOW_AFTER_LNK_DOWN 10 | ||
| 153 | #define WAIT_DCD_HIGH_AFTER_ENABLE_COMM 900 | ||
| 154 | #define MAX_CONF_REQ_WITHOUT_REPLY 10 | ||
| 155 | #define MAX_TERM_REQ_WITHOUT_REPLY 2 | ||
| 156 | #define NUM_CONF_NAK_WITHOUT_REPLY 5 | ||
| 157 | #define NUM_AUTH_REQ_WITHOUT_REPLY 10 | ||
| 158 | |||
| 159 | #define END_OFFSET 0x1F0 | ||
| 160 | |||
| 161 | |||
| 162 | /******Data Structures*****************************************************/ | ||
| 163 | |||
| 164 | /* This structure is placed in the private data area of the device structure. | ||
| 165 | * The card structure used to occupy the private area but now the following | ||
| 166 | * structure will incorporate the card structure along with PPP specific data | ||
| 167 | */ | ||
| 168 | |||
| 169 | typedef struct ppp_private_area | ||
| 170 | { | ||
| 171 | struct net_device *slave; | ||
| 172 | sdla_t* card; | ||
| 173 | unsigned long router_start_time; /*router start time in sec */ | ||
| 174 | unsigned long tick_counter; /*used for 5 second counter*/ | ||
| 175 | unsigned mc; /*multicast support on or off*/ | ||
| 176 | unsigned char enable_IPX; | ||
| 177 | unsigned long network_number; | ||
| 178 | unsigned char pap; | ||
| 179 | unsigned char chap; | ||
| 180 | unsigned char sysname[31]; /* system name for in-bnd auth*/ | ||
| 181 | unsigned char userid[511]; /* list of user ids */ | ||
| 182 | unsigned char passwd[511]; /* list of passwords */ | ||
| 183 | unsigned protocol; /* SKB Protocol */ | ||
| 184 | u32 ip_local; /* Local IP Address */ | ||
| 185 | u32 ip_remote; /* remote IP Address */ | ||
| 186 | |||
| 187 | u32 ip_local_tmp; | ||
| 188 | u32 ip_remote_tmp; | ||
| 189 | |||
| 190 | unsigned char timer_int_enabled; /* Who enabled the timer inter*/ | ||
| 191 | unsigned char update_comms_stats; /* Used by update function */ | ||
| 192 | unsigned long curr_trace_addr; /* Trace information */ | ||
| 193 | unsigned long start_trace_addr; | ||
| 194 | unsigned long end_trace_addr; | ||
| 195 | |||
| 196 | unsigned char interface_down; /* Brind down interface when channel | ||
| 197 | goes down */ | ||
| 198 | unsigned long config_wait_timeout; /* After if_open() if in dynamic if mode, | ||
| 199 | wait a few seconds before configuring */ | ||
| 200 | |||
| 201 | unsigned short udp_pkt_lgth; | ||
| 202 | char udp_pkt_src; | ||
| 203 | char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; | ||
| 204 | |||
| 205 | /* PPP specific statistics */ | ||
| 206 | |||
| 207 | if_send_stat_t if_send_stat; | ||
| 208 | rx_intr_stat_t rx_intr_stat; | ||
| 209 | pipe_mgmt_stat_t pipe_mgmt_stat; | ||
| 210 | |||
| 211 | unsigned long router_up_time; | ||
| 212 | |||
| 213 | /* Polling work queue entry. Each interface | ||
| 214 | * has its own work queue entry, which is used | ||
| 215 | * to defer events from the interrupt */ | ||
| 216 | struct work_struct poll_work; | ||
| 217 | struct timer_list poll_delay_timer; | ||
| 218 | |||
| 219 | u8 gateway; | ||
| 220 | u8 config_ppp; | ||
| 221 | u8 ip_error; | ||
| 222 | |||
| 223 | }ppp_private_area_t; | ||
| 224 | |||
| 225 | /* variable for keeping track of enabling/disabling FT1 monitor status */ | ||
| 226 | static int rCount = 0; | ||
| 227 | |||
| 228 | extern void disable_irq(unsigned int); | ||
| 229 | extern void enable_irq(unsigned int); | ||
| 230 | |||
| 231 | /****** Function Prototypes *************************************************/ | ||
| 232 | |||
| 233 | /* WAN link driver entry points. These are called by the WAN router module. */ | ||
| 234 | static int update(struct wan_device *wandev); | ||
| 235 | static int new_if(struct wan_device *wandev, struct net_device *dev, | ||
| 236 | wanif_conf_t *conf); | ||
| 237 | static int del_if(struct wan_device *wandev, struct net_device *dev); | ||
| 238 | |||
| 239 | /* WANPIPE-specific entry points */ | ||
| 240 | static int wpp_exec (struct sdla *card, void *u_cmd, void *u_data); | ||
| 241 | |||
| 242 | /* Network device interface */ | ||
| 243 | static int if_init(struct net_device *dev); | ||
| 244 | static int if_open(struct net_device *dev); | ||
| 245 | static int if_close(struct net_device *dev); | ||
| 246 | static int if_header(struct sk_buff *skb, struct net_device *dev, | ||
| 247 | unsigned short type, | ||
| 248 | void *daddr, void *saddr, unsigned len); | ||
| 249 | |||
| 250 | static void if_tx_timeout(struct net_device *dev); | ||
| 251 | |||
| 252 | static int if_rebuild_hdr(struct sk_buff *skb); | ||
| 253 | static struct net_device_stats *if_stats(struct net_device *dev); | ||
| 254 | static int if_send(struct sk_buff *skb, struct net_device *dev); | ||
| 255 | |||
| 256 | |||
| 257 | /* PPP firmware interface functions */ | ||
| 258 | static int ppp_read_version(sdla_t *card, char *str); | ||
| 259 | static int ppp_set_outbnd_auth(sdla_t *card, ppp_private_area_t *ppp_priv_area); | ||
| 260 | static int ppp_set_inbnd_auth(sdla_t *card, ppp_private_area_t *ppp_priv_area); | ||
| 261 | static int ppp_configure(sdla_t *card, void *data); | ||
| 262 | static int ppp_set_intr_mode(sdla_t *card, unsigned char mode); | ||
| 263 | static int ppp_comm_enable(sdla_t *card); | ||
| 264 | static int ppp_comm_disable(sdla_t *card); | ||
| 265 | static int ppp_comm_disable_shutdown(sdla_t *card); | ||
| 266 | static int ppp_get_err_stats(sdla_t *card); | ||
| 267 | static int ppp_send(sdla_t *card, void *data, unsigned len, unsigned proto); | ||
| 268 | static int ppp_error(sdla_t *card, int err, ppp_mbox_t *mb); | ||
| 269 | |||
| 270 | static void wpp_isr(sdla_t *card); | ||
| 271 | static void rx_intr(sdla_t *card); | ||
| 272 | static void event_intr(sdla_t *card); | ||
| 273 | static void timer_intr(sdla_t *card); | ||
| 274 | |||
| 275 | /* Background polling routines */ | ||
| 276 | static void process_route(sdla_t *card); | ||
| 277 | static void retrigger_comm(sdla_t *card); | ||
| 278 | |||
| 279 | /* Miscellaneous functions */ | ||
| 280 | static int read_info( sdla_t *card ); | ||
| 281 | static int read_connection_info (sdla_t *card); | ||
| 282 | static void remove_route( sdla_t *card ); | ||
| 283 | static int config508(struct net_device *dev, sdla_t *card); | ||
| 284 | static void show_disc_cause(sdla_t * card, unsigned cause); | ||
| 285 | static int reply_udp( unsigned char *data, unsigned int mbox_len ); | ||
| 286 | static void process_udp_mgmt_pkt(sdla_t *card, struct net_device *dev, | ||
| 287 | ppp_private_area_t *ppp_priv_area); | ||
| 288 | static void init_ppp_tx_rx_buff( sdla_t *card ); | ||
| 289 | static int intr_test( sdla_t *card ); | ||
| 290 | static int udp_pkt_type( struct sk_buff *skb , sdla_t *card); | ||
| 291 | static void init_ppp_priv_struct( ppp_private_area_t *ppp_priv_area); | ||
| 292 | static void init_global_statistics( sdla_t *card ); | ||
| 293 | static int tokenize(char *str, char **tokens); | ||
| 294 | static char* strstrip(char *str, char *s); | ||
| 295 | static int chk_bcast_mcast_addr(sdla_t* card, struct net_device* dev, | ||
| 296 | struct sk_buff *skb); | ||
| 297 | |||
| 298 | static int config_ppp (sdla_t *); | ||
| 299 | static void ppp_poll(struct net_device *dev); | ||
| 300 | static void trigger_ppp_poll(struct net_device *dev); | ||
| 301 | static void ppp_poll_delay (unsigned long dev_ptr); | ||
| 302 | |||
| 303 | |||
| 304 | static int Read_connection_info; | ||
| 305 | static int Intr_test_counter; | ||
| 306 | static unsigned short available_buffer_space; | ||
| 307 | |||
| 308 | |||
| 309 | /* IPX functions */ | ||
| 310 | static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, | ||
| 311 | unsigned char incoming); | ||
| 312 | static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_PX, | ||
| 313 | unsigned long network_number, unsigned short proto); | ||
| 314 | |||
| 315 | /* Lock Functions */ | ||
| 316 | static void s508_lock (sdla_t *card, unsigned long *smp_flags); | ||
| 317 | static void s508_unlock (sdla_t *card, unsigned long *smp_flags); | ||
| 318 | |||
| 319 | static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, | ||
| 320 | struct sk_buff *skb, struct net_device* dev, | ||
| 321 | ppp_private_area_t* ppp_priv_area ); | ||
| 322 | static unsigned short calc_checksum (char *data, int len); | ||
| 323 | static void disable_comm (sdla_t *card); | ||
| 324 | static int detect_and_fix_tx_bug (sdla_t *card); | ||
| 325 | |||
| 326 | /****** Public Functions ****************************************************/ | ||
| 327 | |||
| 328 | /*============================================================================ | ||
| 329 | * PPP protocol initialization routine. | ||
| 330 | * | ||
| 331 | * This routine is called by the main WANPIPE module during setup. At this | ||
| 332 | * point adapter is completely initialized and firmware is running. | ||
| 333 | * o read firmware version (to make sure it's alive) | ||
| 334 | * o configure adapter | ||
| 335 | * o initialize protocol-specific fields of the adapter data space. | ||
| 336 | * | ||
| 337 | * Return: 0 o.k. | ||
| 338 | * < 0 failure. | ||
| 339 | */ | ||
| 340 | int wpp_init(sdla_t *card, wandev_conf_t *conf) | ||
| 341 | { | ||
| 342 | ppp_flags_t *flags; | ||
| 343 | union | ||
| 344 | { | ||
| 345 | char str[80]; | ||
| 346 | } u; | ||
| 347 | |||
| 348 | /* Verify configuration ID */ | ||
| 349 | if (conf->config_id != WANCONFIG_PPP) { | ||
| 350 | |||
| 351 | printk(KERN_INFO "%s: invalid configuration ID %u!\n", | ||
| 352 | card->devname, conf->config_id); | ||
| 353 | return -EINVAL; | ||
| 354 | |||
| 355 | } | ||
| 356 | |||
| 357 | /* Initialize miscellaneous pointers to structures on the adapter */ | ||
| 358 | switch (card->hw.type) { | ||
| 359 | |||
| 360 | case SDLA_S508: | ||
| 361 | card->mbox =(void*)(card->hw.dpmbase + PPP508_MB_OFFS); | ||
| 362 | card->flags=(void*)(card->hw.dpmbase + PPP508_FLG_OFFS); | ||
| 363 | break; | ||
| 364 | |||
| 365 | case SDLA_S514: | ||
| 366 | card->mbox =(void*)(card->hw.dpmbase + PPP514_MB_OFFS); | ||
| 367 | card->flags=(void*)(card->hw.dpmbase + PPP514_FLG_OFFS); | ||
| 368 | break; | ||
| 369 | |||
| 370 | default: | ||
| 371 | return -EINVAL; | ||
| 372 | |||
| 373 | } | ||
| 374 | flags = card->flags; | ||
| 375 | |||
| 376 | /* Read firmware version. Note that when adapter initializes, it | ||
| 377 | * clears the mailbox, so it may appear that the first command was | ||
| 378 | * executed successfully when in fact it was merely erased. To work | ||
| 379 | * around this, we execute the first command twice. | ||
| 380 | */ | ||
| 381 | if (ppp_read_version(card, NULL) || ppp_read_version(card, u.str)) | ||
| 382 | return -EIO; | ||
| 383 | |||
| 384 | printk(KERN_INFO "%s: running PPP firmware v%s\n",card->devname, u.str); | ||
| 385 | /* Adjust configuration and set defaults */ | ||
| 386 | card->wandev.mtu = (conf->mtu) ? | ||
| 387 | min_t(unsigned int, conf->mtu, PPP_MAX_MTU) : PPP_DFLT_MTU; | ||
| 388 | |||
| 389 | card->wandev.bps = conf->bps; | ||
| 390 | card->wandev.interface = conf->interface; | ||
| 391 | card->wandev.clocking = conf->clocking; | ||
| 392 | card->wandev.station = conf->station; | ||
| 393 | card->isr = &wpp_isr; | ||
| 394 | card->poll = NULL; | ||
| 395 | card->exec = &wpp_exec; | ||
| 396 | card->wandev.update = &update; | ||
| 397 | card->wandev.new_if = &new_if; | ||
| 398 | card->wandev.del_if = &del_if; | ||
| 399 | card->wandev.udp_port = conf->udp_port; | ||
| 400 | card->wandev.ttl = conf->ttl; | ||
| 401 | card->wandev.state = WAN_DISCONNECTED; | ||
| 402 | card->disable_comm = &disable_comm; | ||
| 403 | card->irq_dis_if_send_count = 0; | ||
| 404 | card->irq_dis_poll_count = 0; | ||
| 405 | card->u.p.authenticator = conf->u.ppp.authenticator; | ||
| 406 | card->u.p.ip_mode = conf->u.ppp.ip_mode ? | ||
| 407 | conf->u.ppp.ip_mode : WANOPT_PPP_STATIC; | ||
| 408 | card->TracingEnabled = 0; | ||
| 409 | Read_connection_info = 1; | ||
| 410 | |||
| 411 | /* initialize global statistics */ | ||
| 412 | init_global_statistics( card ); | ||
| 413 | |||
| 414 | |||
| 415 | |||
| 416 | if (!card->configured){ | ||
| 417 | int err; | ||
| 418 | |||
| 419 | Intr_test_counter = 0; | ||
| 420 | err = intr_test(card); | ||
| 421 | |||
| 422 | if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { | ||
| 423 | printk("%s: Interrupt Test Failed, Counter: %i\n", | ||
| 424 | card->devname, Intr_test_counter); | ||
| 425 | printk( "%s: Please choose another interrupt\n",card->devname); | ||
| 426 | return -EIO; | ||
| 427 | } | ||
| 428 | |||
| 429 | printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", | ||
| 430 | card->devname, Intr_test_counter); | ||
| 431 | card->configured = 1; | ||
| 432 | } | ||
| 433 | |||
| 434 | ppp_set_intr_mode(card, PPP_INTR_TIMER); | ||
| 435 | |||
| 436 | /* Turn off the transmit and timer interrupt */ | ||
| 437 | flags->imask &= ~PPP_INTR_TIMER; | ||
| 438 | |||
| 439 | printk(KERN_INFO "\n"); | ||
| 440 | |||
| 441 | return 0; | ||
| 442 | } | ||
| 443 | |||
| 444 | /******* WAN Device Driver Entry Points *************************************/ | ||
| 445 | |||
| 446 | /*============================================================================ | ||
| 447 | * Update device status & statistics. | ||
| 448 | */ | ||
| 449 | static int update(struct wan_device *wandev) | ||
| 450 | { | ||
| 451 | sdla_t* card = wandev->private; | ||
| 452 | struct net_device* dev; | ||
| 453 | volatile ppp_private_area_t *ppp_priv_area; | ||
| 454 | ppp_flags_t *flags = card->flags; | ||
| 455 | unsigned long timeout; | ||
| 456 | |||
| 457 | /* sanity checks */ | ||
| 458 | if ((wandev == NULL) || (wandev->private == NULL)) | ||
| 459 | return -EFAULT; | ||
| 460 | |||
| 461 | if (wandev->state == WAN_UNCONFIGURED) | ||
| 462 | return -ENODEV; | ||
| 463 | |||
| 464 | /* Shutdown bug fix. This function can be | ||
| 465 | * called with NULL dev pointer during | ||
| 466 | * shutdown | ||
| 467 | */ | ||
| 468 | if ((dev=card->wandev.dev) == NULL){ | ||
| 469 | return -ENODEV; | ||
| 470 | } | ||
| 471 | |||
| 472 | if ((ppp_priv_area=dev->priv) == NULL){ | ||
| 473 | return -ENODEV; | ||
| 474 | } | ||
| 475 | |||
| 476 | ppp_priv_area->update_comms_stats = 2; | ||
| 477 | ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_UPDATE; | ||
| 478 | flags->imask |= PPP_INTR_TIMER; | ||
| 479 | |||
| 480 | /* wait a maximum of 1 second for the statistics to be updated */ | ||
| 481 | timeout = jiffies; | ||
| 482 | for(;;) { | ||
| 483 | if(ppp_priv_area->update_comms_stats == 0){ | ||
| 484 | break; | ||
| 485 | } | ||
| 486 | if (time_after(jiffies, timeout + 1 * HZ)){ | ||
| 487 | ppp_priv_area->update_comms_stats = 0; | ||
| 488 | ppp_priv_area->timer_int_enabled &= | ||
| 489 | ~TMR_INT_ENABLED_UPDATE; | ||
| 490 | return -EAGAIN; | ||
| 491 | } | ||
| 492 | } | ||
| 493 | |||
| 494 | return 0; | ||
| 495 | } | ||
| 496 | |||
| 497 | /*============================================================================ | ||
| 498 | * Create new logical channel. | ||
| 499 | * This routine is called by the router when ROUTER_IFNEW IOCTL is being | ||
| 500 | * handled. | ||
| 501 | * o parse media- and hardware-specific configuration | ||
| 502 | * o make sure that a new channel can be created | ||
| 503 | * o allocate resources, if necessary | ||
| 504 | * o prepare network device structure for registaration. | ||
| 505 | * | ||
| 506 | * Return: 0 o.k. | ||
| 507 | * < 0 failure (channel will not be created) | ||
| 508 | */ | ||
| 509 | static int new_if(struct wan_device *wandev, struct net_device *dev, | ||
| 510 | wanif_conf_t *conf) | ||
| 511 | { | ||
| 512 | sdla_t *card = wandev->private; | ||
| 513 | ppp_private_area_t *ppp_priv_area; | ||
| 514 | |||
| 515 | if (wandev->ndev) | ||
| 516 | return -EEXIST; | ||
| 517 | |||
| 518 | |||
| 519 | printk(KERN_INFO "%s: Configuring Interface: %s\n", | ||
| 520 | card->devname, conf->name); | ||
| 521 | |||
| 522 | if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { | ||
| 523 | |||
| 524 | printk(KERN_INFO "%s: Invalid interface name!\n", | ||
| 525 | card->devname); | ||
| 526 | return -EINVAL; | ||
| 527 | |||
| 528 | } | ||
| 529 | |||
| 530 | /* allocate and initialize private data */ | ||
| 531 | ppp_priv_area = kmalloc(sizeof(ppp_private_area_t), GFP_KERNEL); | ||
| 532 | |||
| 533 | if( ppp_priv_area == NULL ) | ||
| 534 | return -ENOMEM; | ||
| 535 | |||
| 536 | memset(ppp_priv_area, 0, sizeof(ppp_private_area_t)); | ||
| 537 | |||
| 538 | ppp_priv_area->card = card; | ||
| 539 | |||
| 540 | /* initialize data */ | ||
| 541 | strcpy(card->u.p.if_name, conf->name); | ||
| 542 | |||
| 543 | /* initialize data in ppp_private_area structure */ | ||
| 544 | |||
| 545 | init_ppp_priv_struct( ppp_priv_area ); | ||
| 546 | |||
| 547 | ppp_priv_area->mc = conf->mc; | ||
| 548 | ppp_priv_area->pap = conf->pap; | ||
| 549 | ppp_priv_area->chap = conf->chap; | ||
| 550 | |||
| 551 | /* Option to bring down the interface when | ||
| 552 | * the link goes down */ | ||
| 553 | if (conf->if_down){ | ||
| 554 | set_bit(DYN_OPT_ON,&ppp_priv_area->interface_down); | ||
| 555 | printk("%s: Dynamic interface configuration enabled\n", | ||
| 556 | card->devname); | ||
| 557 | } | ||
| 558 | |||
| 559 | /* If no user ids are specified */ | ||
| 560 | if(!strlen(conf->userid) && (ppp_priv_area->pap||ppp_priv_area->chap)){ | ||
| 561 | kfree(ppp_priv_area); | ||
| 562 | return -EINVAL; | ||
| 563 | } | ||
| 564 | |||
| 565 | /* If no passwords are specified */ | ||
| 566 | if(!strlen(conf->passwd) && (ppp_priv_area->pap||ppp_priv_area->chap)){ | ||
| 567 | kfree(ppp_priv_area); | ||
| 568 | return -EINVAL; | ||
| 569 | } | ||
| 570 | |||
| 571 | if(strlen(conf->sysname) > 31){ | ||
| 572 | kfree(ppp_priv_area); | ||
| 573 | return -EINVAL; | ||
| 574 | } | ||
| 575 | |||
| 576 | /* If no system name is specified */ | ||
| 577 | if(!strlen(conf->sysname) && (card->u.p.authenticator)){ | ||
| 578 | kfree(ppp_priv_area); | ||
| 579 | return -EINVAL; | ||
| 580 | } | ||
| 581 | |||
| 582 | /* copy the data into the ppp private structure */ | ||
| 583 | memcpy(ppp_priv_area->userid, conf->userid, strlen(conf->userid)); | ||
| 584 | memcpy(ppp_priv_area->passwd, conf->passwd, strlen(conf->passwd)); | ||
| 585 | memcpy(ppp_priv_area->sysname, conf->sysname, strlen(conf->sysname)); | ||
| 586 | |||
| 587 | |||
| 588 | ppp_priv_area->enable_IPX = conf->enable_IPX; | ||
| 589 | if (conf->network_number){ | ||
| 590 | ppp_priv_area->network_number = conf->network_number; | ||
| 591 | }else{ | ||
| 592 | ppp_priv_area->network_number = 0xDEADBEEF; | ||
| 593 | } | ||
| 594 | |||
| 595 | /* Tells us that if this interface is a | ||
| 596 | * gateway or not */ | ||
| 597 | if ((ppp_priv_area->gateway = conf->gateway) == WANOPT_YES){ | ||
| 598 | printk(KERN_INFO "%s: Interface %s is set as a gateway.\n", | ||
| 599 | card->devname,card->u.p.if_name); | ||
| 600 | } | ||
| 601 | |||
| 602 | /* prepare network device data space for registration */ | ||
| 603 | strcpy(dev->name,card->u.p.if_name); | ||
| 604 | |||
| 605 | dev->init = &if_init; | ||
| 606 | dev->priv = ppp_priv_area; | ||
| 607 | dev->mtu = min_t(unsigned int, dev->mtu, card->wandev.mtu); | ||
| 608 | |||
| 609 | /* Initialize the polling work routine */ | ||
| 610 | INIT_WORK(&ppp_priv_area->poll_work, (void*)(void*)ppp_poll, dev); | ||
| 611 | |||
| 612 | /* Initialize the polling delay timer */ | ||
| 613 | init_timer(&ppp_priv_area->poll_delay_timer); | ||
| 614 | ppp_priv_area->poll_delay_timer.data = (unsigned long)dev; | ||
| 615 | ppp_priv_area->poll_delay_timer.function = ppp_poll_delay; | ||
| 616 | |||
| 617 | |||
| 618 | /* Since we start with dummy IP addresses we can say | ||
| 619 | * that route exists */ | ||
| 620 | printk(KERN_INFO "\n"); | ||
| 621 | |||
| 622 | return 0; | ||
| 623 | } | ||
| 624 | |||
| 625 | /*============================================================================ | ||
| 626 | * Delete logical channel. | ||
| 627 | */ | ||
| 628 | static int del_if(struct wan_device *wandev, struct net_device *dev) | ||
| 629 | { | ||
| 630 | return 0; | ||
| 631 | } | ||
| 632 | |||
| 633 | static void disable_comm (sdla_t *card) | ||
| 634 | { | ||
| 635 | ppp_comm_disable_shutdown(card); | ||
| 636 | return; | ||
| 637 | } | ||
| 638 | |||
| 639 | /****** WANPIPE-specific entry points ***************************************/ | ||
| 640 | |||
| 641 | /*============================================================================ | ||
| 642 | * Execute adapter interface command. | ||
| 643 | */ | ||
| 644 | |||
| 645 | //FIXME: Why do we need this ???? | ||
| 646 | static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data) | ||
| 647 | { | ||
| 648 | ppp_mbox_t *mbox = card->mbox; | ||
| 649 | int len; | ||
| 650 | |||
| 651 | if (copy_from_user((void*)&mbox->cmd, u_cmd, sizeof(ppp_cmd_t))) | ||
| 652 | return -EFAULT; | ||
| 653 | |||
| 654 | len = mbox->cmd.length; | ||
| 655 | |||
| 656 | if (len) { | ||
| 657 | |||
| 658 | if( copy_from_user((void*)&mbox->data, u_data, len)) | ||
| 659 | return -EFAULT; | ||
| 660 | |||
| 661 | } | ||
| 662 | |||
| 663 | /* execute command */ | ||
| 664 | if (!sdla_exec(mbox)) | ||
| 665 | return -EIO; | ||
| 666 | |||
| 667 | /* return result */ | ||
| 668 | if( copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(ppp_cmd_t))) | ||
| 669 | return -EFAULT; | ||
| 670 | len = mbox->cmd.length; | ||
| 671 | |||
| 672 | if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len)) | ||
| 673 | return -EFAULT; | ||
| 674 | |||
| 675 | return 0; | ||
| 676 | } | ||
| 677 | |||
| 678 | /****** Network Device Interface ********************************************/ | ||
| 679 | |||
| 680 | /*============================================================================ | ||
| 681 | * Initialize Linux network interface. | ||
| 682 | * | ||
| 683 | * This routine is called only once for each interface, during Linux network | ||
| 684 | * interface registration. Returning anything but zero will fail interface | ||
| 685 | * registration. | ||
| 686 | */ | ||
| 687 | static int if_init(struct net_device *dev) | ||
| 688 | { | ||
| 689 | ppp_private_area_t *ppp_priv_area = dev->priv; | ||
| 690 | sdla_t *card = ppp_priv_area->card; | ||
| 691 | struct wan_device *wandev = &card->wandev; | ||
| 692 | |||
| 693 | /* Initialize device driver entry points */ | ||
| 694 | dev->open = &if_open; | ||
| 695 | dev->stop = &if_close; | ||
| 696 | dev->hard_header = &if_header; | ||
| 697 | dev->rebuild_header = &if_rebuild_hdr; | ||
| 698 | dev->hard_start_xmit = &if_send; | ||
| 699 | dev->get_stats = &if_stats; | ||
| 700 | dev->tx_timeout = &if_tx_timeout; | ||
| 701 | dev->watchdog_timeo = TX_TIMEOUT; | ||
| 702 | |||
| 703 | /* Initialize media-specific parameters */ | ||
| 704 | dev->type = ARPHRD_PPP; /* ARP h/w type */ | ||
| 705 | dev->flags |= IFF_POINTOPOINT; | ||
| 706 | dev->flags |= IFF_NOARP; | ||
| 707 | |||
| 708 | /* Enable Mulitcasting if specified by user*/ | ||
| 709 | if (ppp_priv_area->mc == WANOPT_YES){ | ||
| 710 | dev->flags |= IFF_MULTICAST; | ||
| 711 | } | ||
| 712 | |||
| 713 | dev->mtu = wandev->mtu; | ||
| 714 | dev->hard_header_len = PPP_HDR_LEN; /* media header length */ | ||
| 715 | |||
| 716 | /* Initialize hardware parameters (just for reference) */ | ||
| 717 | dev->irq = wandev->irq; | ||
| 718 | dev->dma = wandev->dma; | ||
| 719 | dev->base_addr = wandev->ioport; | ||
| 720 | dev->mem_start = wandev->maddr; | ||
| 721 | dev->mem_end = wandev->maddr + wandev->msize - 1; | ||
| 722 | |||
| 723 | /* Set transmit buffer queue length */ | ||
| 724 | dev->tx_queue_len = 100; | ||
| 725 | SET_MODULE_OWNER(dev); | ||
| 726 | |||
| 727 | return 0; | ||
| 728 | } | ||
| 729 | |||
| 730 | /*============================================================================ | ||
| 731 | * Open network interface. | ||
| 732 | * o enable communications and interrupts. | ||
| 733 | * o prevent module from unloading by incrementing use count | ||
| 734 | * | ||
| 735 | * Return 0 if O.k. or errno. | ||
| 736 | */ | ||
| 737 | static int if_open(struct net_device *dev) | ||
| 738 | { | ||
| 739 | ppp_private_area_t *ppp_priv_area = dev->priv; | ||
| 740 | sdla_t *card = ppp_priv_area->card; | ||
| 741 | struct timeval tv; | ||
| 742 | //unsigned long smp_flags; | ||
| 743 | |||
| 744 | if (netif_running(dev)) | ||
| 745 | return -EBUSY; | ||
| 746 | |||
| 747 | wanpipe_open(card); | ||
| 748 | |||
| 749 | netif_start_queue(dev); | ||
| 750 | |||
| 751 | do_gettimeofday( &tv ); | ||
| 752 | ppp_priv_area->router_start_time = tv.tv_sec; | ||
| 753 | |||
| 754 | /* We cannot configure the card here because we don't | ||
| 755 | * have access to the interface IP addresses. | ||
| 756 | * Once the interface initilization is complete, we will be | ||
| 757 | * able to access the IP addresses. Therefore, | ||
| 758 | * configure the ppp link in the poll routine */ | ||
| 759 | set_bit(0,&ppp_priv_area->config_ppp); | ||
| 760 | ppp_priv_area->config_wait_timeout=jiffies; | ||
| 761 | |||
| 762 | /* Start the PPP configuration after 1sec delay. | ||
| 763 | * This will give the interface initilization time | ||
| 764 | * to finish its configuration */ | ||
| 765 | mod_timer(&ppp_priv_area->poll_delay_timer, jiffies + HZ); | ||
| 766 | return 0; | ||
| 767 | } | ||
| 768 | |||
| 769 | /*============================================================================ | ||
| 770 | * Close network interface. | ||
| 771 | * o if this is the last open, then disable communications and interrupts. | ||
| 772 | * o reset flags. | ||
| 773 | */ | ||
| 774 | static int if_close(struct net_device *dev) | ||
| 775 | { | ||
| 776 | ppp_private_area_t *ppp_priv_area = dev->priv; | ||
| 777 | sdla_t *card = ppp_priv_area->card; | ||
| 778 | |||
| 779 | netif_stop_queue(dev); | ||
| 780 | wanpipe_close(card); | ||
| 781 | |||
| 782 | del_timer (&ppp_priv_area->poll_delay_timer); | ||
| 783 | return 0; | ||
| 784 | } | ||
| 785 | |||
| 786 | /*============================================================================ | ||
| 787 | * Build media header. | ||
| 788 | * | ||
| 789 | * The trick here is to put packet type (Ethertype) into 'protocol' field of | ||
| 790 | * the socket buffer, so that we don't forget it. If packet type is not | ||
| 791 | * supported, set skb->protocol to 0 and discard packet later. | ||
| 792 | * | ||
| 793 | * Return: media header length. | ||
| 794 | */ | ||
| 795 | static int if_header(struct sk_buff *skb, struct net_device *dev, | ||
| 796 | unsigned short type, void *daddr, void *saddr, unsigned len) | ||
| 797 | { | ||
| 798 | switch (type) | ||
| 799 | { | ||
| 800 | case ETH_P_IP: | ||
| 801 | case ETH_P_IPX: | ||
| 802 | skb->protocol = htons(type); | ||
| 803 | break; | ||
| 804 | |||
| 805 | default: | ||
| 806 | skb->protocol = 0; | ||
| 807 | } | ||
| 808 | |||
| 809 | return PPP_HDR_LEN; | ||
| 810 | } | ||
| 811 | |||
| 812 | /*============================================================================ | ||
| 813 | * Re-build media header. | ||
| 814 | * | ||
| 815 | * Return: 1 physical address resolved. | ||
| 816 | * 0 physical address not resolved | ||
| 817 | */ | ||
| 818 | static int if_rebuild_hdr (struct sk_buff *skb) | ||
| 819 | { | ||
| 820 | struct net_device *dev = skb->dev; | ||
| 821 | ppp_private_area_t *ppp_priv_area = dev->priv; | ||
| 822 | sdla_t *card = ppp_priv_area->card; | ||
| 823 | |||
| 824 | printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", | ||
| 825 | card->devname, dev->name); | ||
| 826 | return 1; | ||
| 827 | } | ||
| 828 | |||
| 829 | /*============================================================================ | ||
| 830 | * Handle transmit timeout event from netif watchdog | ||
| 831 | */ | ||
| 832 | static void if_tx_timeout(struct net_device *dev) | ||
| 833 | { | ||
| 834 | ppp_private_area_t* chan = dev->priv; | ||
| 835 | sdla_t *card = chan->card; | ||
| 836 | |||
| 837 | /* If our device stays busy for at least 5 seconds then we will | ||
| 838 | * kick start the device by making dev->tbusy = 0. We expect | ||
| 839 | * that our device never stays busy more than 5 seconds. So this | ||
| 840 | * is only used as a last resort. | ||
| 841 | */ | ||
| 842 | |||
| 843 | ++ chan->if_send_stat.if_send_tbusy; | ||
| 844 | ++card->wandev.stats.collisions; | ||
| 845 | |||
| 846 | printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); | ||
| 847 | ++chan->if_send_stat.if_send_tbusy_timeout; | ||
| 848 | netif_wake_queue (dev); | ||
| 849 | } | ||
| 850 | |||
| 851 | |||
| 852 | |||
| 853 | /*============================================================================ | ||
| 854 | * Send a packet on a network interface. | ||
| 855 | * o set tbusy flag (marks start of the transmission) to block a timer-based | ||
| 856 | * transmit from overlapping. | ||
| 857 | * o check link state. If link is not up, then drop the packet. | ||
| 858 | * o execute adapter send command. | ||
| 859 | * o free socket buffer | ||
| 860 | * | ||
| 861 | * Return: 0 complete (socket buffer must be freed) | ||
| 862 | * non-0 packet may be re-transmitted (tbusy must be set) | ||
| 863 | * | ||
| 864 | * Notes: | ||
| 865 | * 1. This routine is called either by the protocol stack or by the "net | ||
| 866 | * bottom half" (with interrupts enabled). | ||
| 867 | * 2. Setting tbusy flag will inhibit further transmit requests from the | ||
| 868 | * protocol stack and can be used for flow control with protocol layer. | ||
| 869 | */ | ||
| 870 | static int if_send (struct sk_buff *skb, struct net_device *dev) | ||
| 871 | { | ||
| 872 | ppp_private_area_t *ppp_priv_area = dev->priv; | ||
| 873 | sdla_t *card = ppp_priv_area->card; | ||
| 874 | unsigned char *sendpacket; | ||
| 875 | unsigned long smp_flags; | ||
| 876 | ppp_flags_t *flags = card->flags; | ||
| 877 | int udp_type; | ||
| 878 | int err=0; | ||
| 879 | |||
| 880 | ++ppp_priv_area->if_send_stat.if_send_entry; | ||
| 881 | |||
| 882 | netif_stop_queue(dev); | ||
| 883 | |||
| 884 | if (skb == NULL) { | ||
| 885 | |||
| 886 | /* If we get here, some higher layer thinks we've missed an | ||
| 887 | * tx-done interrupt. | ||
| 888 | */ | ||
| 889 | printk(KERN_INFO "%s: interface %s got kicked!\n", | ||
| 890 | card->devname, dev->name); | ||
| 891 | |||
| 892 | ++ppp_priv_area->if_send_stat.if_send_skb_null; | ||
| 893 | |||
| 894 | netif_wake_queue(dev); | ||
| 895 | return 0; | ||
| 896 | } | ||
| 897 | |||
| 898 | sendpacket = skb->data; | ||
| 899 | |||
| 900 | udp_type = udp_pkt_type( skb, card ); | ||
| 901 | |||
| 902 | |||
| 903 | if (udp_type == UDP_PTPIPE_TYPE){ | ||
| 904 | if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, | ||
| 905 | ppp_priv_area)){ | ||
| 906 | flags->imask |= PPP_INTR_TIMER; | ||
| 907 | } | ||
| 908 | ++ppp_priv_area->if_send_stat.if_send_PIPE_request; | ||
| 909 | netif_start_queue(dev); | ||
| 910 | return 0; | ||
| 911 | } | ||
| 912 | |||
| 913 | /* Check for broadcast and multicast addresses | ||
| 914 | * If found, drop (deallocate) a packet and return. | ||
| 915 | */ | ||
| 916 | if(chk_bcast_mcast_addr(card, dev, skb)){ | ||
| 917 | ++card->wandev.stats.tx_dropped; | ||
| 918 | dev_kfree_skb_any(skb); | ||
| 919 | netif_start_queue(dev); | ||
| 920 | return 0; | ||
| 921 | } | ||
| 922 | |||
| 923 | |||
| 924 | if(card->hw.type != SDLA_S514){ | ||
| 925 | s508_lock(card,&smp_flags); | ||
| 926 | } | ||
| 927 | |||
| 928 | if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) { | ||
| 929 | |||
| 930 | printk(KERN_INFO "%s: Critical in if_send: %lx\n", | ||
| 931 | card->wandev.name,card->wandev.critical); | ||
| 932 | |||
| 933 | ++card->wandev.stats.tx_dropped; | ||
| 934 | ++ppp_priv_area->if_send_stat.if_send_critical_non_ISR; | ||
| 935 | netif_start_queue(dev); | ||
| 936 | goto if_send_exit_crit; | ||
| 937 | } | ||
| 938 | |||
| 939 | if (card->wandev.state != WAN_CONNECTED) { | ||
| 940 | |||
| 941 | ++ppp_priv_area->if_send_stat.if_send_wan_disconnected; | ||
| 942 | ++card->wandev.stats.tx_dropped; | ||
| 943 | netif_start_queue(dev); | ||
| 944 | |||
| 945 | } else if (!skb->protocol) { | ||
| 946 | ++ppp_priv_area->if_send_stat.if_send_protocol_error; | ||
| 947 | ++card->wandev.stats.tx_errors; | ||
| 948 | netif_start_queue(dev); | ||
| 949 | |||
| 950 | } else { | ||
| 951 | |||
| 952 | /*If it's IPX change the network numbers to 0 if they're ours.*/ | ||
| 953 | if( skb->protocol == htons(ETH_P_IPX) ) { | ||
| 954 | if(ppp_priv_area->enable_IPX) { | ||
| 955 | switch_net_numbers( skb->data, | ||
| 956 | ppp_priv_area->network_number, 0); | ||
| 957 | } else { | ||
| 958 | ++card->wandev.stats.tx_dropped; | ||
| 959 | netif_start_queue(dev); | ||
| 960 | goto if_send_exit_crit; | ||
| 961 | } | ||
| 962 | } | ||
| 963 | |||
| 964 | if (ppp_send(card, skb->data, skb->len, skb->protocol)) { | ||
| 965 | netif_stop_queue(dev); | ||
| 966 | ++ppp_priv_area->if_send_stat.if_send_adptr_bfrs_full; | ||
| 967 | ++ppp_priv_area->if_send_stat.if_send_tx_int_enabled; | ||
| 968 | } else { | ||
| 969 | ++ppp_priv_area->if_send_stat.if_send_bfr_passed_to_adptr; | ||
| 970 | ++card->wandev.stats.tx_packets; | ||
| 971 | card->wandev.stats.tx_bytes += skb->len; | ||
| 972 | netif_start_queue(dev); | ||
| 973 | dev->trans_start = jiffies; | ||
| 974 | } | ||
| 975 | } | ||
| 976 | |||
| 977 | if_send_exit_crit: | ||
| 978 | |||
| 979 | if (!(err=netif_queue_stopped(dev))){ | ||
| 980 | dev_kfree_skb_any(skb); | ||
| 981 | }else{ | ||
| 982 | ppp_priv_area->tick_counter = jiffies; | ||
| 983 | flags->imask |= PPP_INTR_TXRDY; /* unmask Tx interrupts */ | ||
| 984 | } | ||
| 985 | |||
| 986 | clear_bit(SEND_CRIT,&card->wandev.critical); | ||
| 987 | if(card->hw.type != SDLA_S514){ | ||
| 988 | s508_unlock(card,&smp_flags); | ||
| 989 | } | ||
| 990 | |||
| 991 | return err; | ||
| 992 | } | ||
| 993 | |||
| 994 | |||
| 995 | /*============================================================================= | ||
| 996 | * Store a UDP management packet for later processing. | ||
| 997 | */ | ||
| 998 | |||
| 999 | static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, | ||
| 1000 | struct sk_buff *skb, struct net_device* dev, | ||
| 1001 | ppp_private_area_t* ppp_priv_area ) | ||
| 1002 | { | ||
| 1003 | int udp_pkt_stored = 0; | ||
| 1004 | |||
| 1005 | if(!ppp_priv_area->udp_pkt_lgth && (skb->len<=MAX_LGTH_UDP_MGNT_PKT)){ | ||
| 1006 | ppp_priv_area->udp_pkt_lgth = skb->len; | ||
| 1007 | ppp_priv_area->udp_pkt_src = udp_pkt_src; | ||
| 1008 | memcpy(ppp_priv_area->udp_pkt_data, skb->data, skb->len); | ||
| 1009 | ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_UDP; | ||
| 1010 | ppp_priv_area->protocol = skb->protocol; | ||
| 1011 | udp_pkt_stored = 1; | ||
| 1012 | }else{ | ||
| 1013 | if (skb->len > MAX_LGTH_UDP_MGNT_PKT){ | ||
| 1014 | printk(KERN_INFO "%s: PIPEMON UDP request too long : %i\n", | ||
| 1015 | card->devname, skb->len); | ||
| 1016 | }else{ | ||
| 1017 | printk(KERN_INFO "%s: PIPEMON UPD request already pending\n", | ||
| 1018 | card->devname); | ||
| 1019 | } | ||
| 1020 | ppp_priv_area->udp_pkt_lgth = 0; | ||
| 1021 | } | ||
| 1022 | |||
| 1023 | if(udp_pkt_src == UDP_PKT_FRM_STACK){ | ||
| 1024 | dev_kfree_skb_any(skb); | ||
| 1025 | }else{ | ||
| 1026 | dev_kfree_skb_any(skb); | ||
| 1027 | } | ||
| 1028 | |||
| 1029 | return(udp_pkt_stored); | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | |||
| 1033 | |||
| 1034 | /*============================================================================ | ||
| 1035 | * Reply to UDP Management system. | ||
| 1036 | * Return length of reply. | ||
| 1037 | */ | ||
| 1038 | static int reply_udp( unsigned char *data, unsigned int mbox_len ) | ||
| 1039 | { | ||
| 1040 | unsigned short len, udp_length, temp, ip_length; | ||
| 1041 | unsigned long ip_temp; | ||
| 1042 | int even_bound = 0; | ||
| 1043 | ppp_udp_pkt_t *p_udp_pkt = (ppp_udp_pkt_t *)data; | ||
| 1044 | |||
| 1045 | /* Set length of packet */ | ||
| 1046 | len = sizeof(ip_pkt_t)+ | ||
| 1047 | sizeof(udp_pkt_t)+ | ||
| 1048 | sizeof(wp_mgmt_t)+ | ||
| 1049 | sizeof(cblock_t)+ | ||
| 1050 | mbox_len; | ||
| 1051 | |||
| 1052 | /* fill in UDP reply */ | ||
| 1053 | p_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; | ||
| 1054 | |||
| 1055 | /* fill in UDP length */ | ||
| 1056 | udp_length = sizeof(udp_pkt_t)+ | ||
| 1057 | sizeof(wp_mgmt_t)+ | ||
| 1058 | sizeof(cblock_t)+ | ||
| 1059 | mbox_len; | ||
| 1060 | |||
| 1061 | |||
| 1062 | /* put it on an even boundary */ | ||
| 1063 | if ( udp_length & 0x0001 ) { | ||
| 1064 | udp_length += 1; | ||
| 1065 | len += 1; | ||
| 1066 | even_bound=1; | ||
| 1067 | } | ||
| 1068 | |||
| 1069 | temp = (udp_length<<8)|(udp_length>>8); | ||
| 1070 | p_udp_pkt->udp_pkt.udp_length = temp; | ||
| 1071 | |||
| 1072 | |||
| 1073 | /* swap UDP ports */ | ||
| 1074 | temp = p_udp_pkt->udp_pkt.udp_src_port; | ||
| 1075 | p_udp_pkt->udp_pkt.udp_src_port = | ||
| 1076 | p_udp_pkt->udp_pkt.udp_dst_port; | ||
| 1077 | p_udp_pkt->udp_pkt.udp_dst_port = temp; | ||
| 1078 | |||
| 1079 | |||
| 1080 | /* add UDP pseudo header */ | ||
| 1081 | temp = 0x1100; | ||
| 1082 | *((unsigned short *)(p_udp_pkt->data+mbox_len+even_bound)) = temp; | ||
| 1083 | temp = (udp_length<<8)|(udp_length>>8); | ||
| 1084 | *((unsigned short *)(p_udp_pkt->data+mbox_len+even_bound+2)) = temp; | ||
| 1085 | |||
| 1086 | /* calculate UDP checksum */ | ||
| 1087 | p_udp_pkt->udp_pkt.udp_checksum = 0; | ||
| 1088 | p_udp_pkt->udp_pkt.udp_checksum = | ||
| 1089 | calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET); | ||
| 1090 | |||
| 1091 | /* fill in IP length */ | ||
| 1092 | ip_length = udp_length + sizeof(ip_pkt_t); | ||
| 1093 | temp = (ip_length<<8)|(ip_length>>8); | ||
| 1094 | p_udp_pkt->ip_pkt.total_length = temp; | ||
| 1095 | |||
| 1096 | /* swap IP addresses */ | ||
| 1097 | ip_temp = p_udp_pkt->ip_pkt.ip_src_address; | ||
| 1098 | p_udp_pkt->ip_pkt.ip_src_address = p_udp_pkt->ip_pkt.ip_dst_address; | ||
| 1099 | p_udp_pkt->ip_pkt.ip_dst_address = ip_temp; | ||
| 1100 | |||
| 1101 | /* fill in IP checksum */ | ||
| 1102 | p_udp_pkt->ip_pkt.hdr_checksum = 0; | ||
| 1103 | p_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data,sizeof(ip_pkt_t)); | ||
| 1104 | |||
| 1105 | return len; | ||
| 1106 | |||
| 1107 | } /* reply_udp */ | ||
| 1108 | |||
| 1109 | unsigned short calc_checksum (char *data, int len) | ||
| 1110 | { | ||
| 1111 | unsigned short temp; | ||
| 1112 | unsigned long sum=0; | ||
| 1113 | int i; | ||
| 1114 | |||
| 1115 | for( i = 0; i <len; i+=2 ) { | ||
| 1116 | memcpy(&temp,&data[i],2); | ||
| 1117 | sum += (unsigned long)temp; | ||
| 1118 | } | ||
| 1119 | |||
| 1120 | while (sum >> 16 ) { | ||
| 1121 | sum = (sum & 0xffffUL) + (sum >> 16); | ||
| 1122 | } | ||
| 1123 | |||
| 1124 | temp = (unsigned short)sum; | ||
| 1125 | temp = ~temp; | ||
| 1126 | |||
| 1127 | if( temp == 0 ) | ||
| 1128 | temp = 0xffff; | ||
| 1129 | |||
| 1130 | return temp; | ||
| 1131 | } | ||
| 1132 | |||
| 1133 | /* | ||
| 1134 | If incoming is 0 (outgoing)- if the net numbers is ours make it 0 | ||
| 1135 | if incoming is 1 - if the net number is 0 make it ours | ||
| 1136 | |||
| 1137 | */ | ||
| 1138 | static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) | ||
| 1139 | { | ||
| 1140 | unsigned long pnetwork_number; | ||
| 1141 | |||
| 1142 | pnetwork_number = (unsigned long)((sendpacket[6] << 24) + | ||
| 1143 | (sendpacket[7] << 16) + (sendpacket[8] << 8) + | ||
| 1144 | sendpacket[9]); | ||
| 1145 | |||
| 1146 | if (!incoming) { | ||
| 1147 | //If the destination network number is ours, make it 0 | ||
| 1148 | if( pnetwork_number == network_number) { | ||
| 1149 | sendpacket[6] = sendpacket[7] = sendpacket[8] = | ||
| 1150 | sendpacket[9] = 0x00; | ||
| 1151 | } | ||
| 1152 | } else { | ||
| 1153 | //If the incoming network is 0, make it ours | ||
| 1154 | if( pnetwork_number == 0) { | ||
| 1155 | sendpacket[6] = (unsigned char)(network_number >> 24); | ||
| 1156 | sendpacket[7] = (unsigned char)((network_number & | ||
| 1157 | 0x00FF0000) >> 16); | ||
| 1158 | sendpacket[8] = (unsigned char)((network_number & | ||
| 1159 | 0x0000FF00) >> 8); | ||
| 1160 | sendpacket[9] = (unsigned char)(network_number & | ||
| 1161 | 0x000000FF); | ||
| 1162 | } | ||
| 1163 | } | ||
| 1164 | |||
| 1165 | |||
| 1166 | pnetwork_number = (unsigned long)((sendpacket[18] << 24) + | ||
| 1167 | (sendpacket[19] << 16) + (sendpacket[20] << 8) + | ||
| 1168 | sendpacket[21]); | ||
| 1169 | |||
| 1170 | if( !incoming ) { | ||
| 1171 | //If the source network is ours, make it 0 | ||
| 1172 | if( pnetwork_number == network_number) { | ||
| 1173 | sendpacket[18] = sendpacket[19] = sendpacket[20] = | ||
| 1174 | sendpacket[21] = 0x00; | ||
| 1175 | } | ||
| 1176 | } else { | ||
| 1177 | //If the source network is 0, make it ours | ||
| 1178 | if( pnetwork_number == 0 ) { | ||
| 1179 | sendpacket[18] = (unsigned char)(network_number >> 24); | ||
| 1180 | sendpacket[19] = (unsigned char)((network_number & | ||
| 1181 | 0x00FF0000) >> 16); | ||
| 1182 | sendpacket[20] = (unsigned char)((network_number & | ||
| 1183 | 0x0000FF00) >> 8); | ||
| 1184 | sendpacket[21] = (unsigned char)(network_number & | ||
| 1185 | 0x000000FF); | ||
| 1186 | } | ||
| 1187 | } | ||
| 1188 | } /* switch_net_numbers */ | ||
| 1189 | |||
| 1190 | /*============================================================================ | ||
| 1191 | * Get ethernet-style interface statistics. | ||
| 1192 | * Return a pointer to struct net_device_stats. | ||
| 1193 | */ | ||
| 1194 | static struct net_device_stats *if_stats(struct net_device *dev) | ||
| 1195 | { | ||
| 1196 | |||
| 1197 | ppp_private_area_t *ppp_priv_area = dev->priv; | ||
| 1198 | sdla_t* card; | ||
| 1199 | |||
| 1200 | if( ppp_priv_area == NULL ) | ||
| 1201 | return NULL; | ||
| 1202 | |||
| 1203 | card = ppp_priv_area->card; | ||
| 1204 | return &card->wandev.stats; | ||
| 1205 | } | ||
| 1206 | |||
| 1207 | /****** PPP Firmware Interface Functions ************************************/ | ||
| 1208 | |||
| 1209 | /*============================================================================ | ||
| 1210 | * Read firmware code version. | ||
| 1211 | * Put code version as ASCII string in str. | ||
| 1212 | */ | ||
| 1213 | static int ppp_read_version(sdla_t *card, char *str) | ||
| 1214 | { | ||
| 1215 | ppp_mbox_t *mb = card->mbox; | ||
| 1216 | int err; | ||
| 1217 | |||
| 1218 | memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); | ||
| 1219 | mb->cmd.command = PPP_READ_CODE_VERSION; | ||
| 1220 | err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; | ||
| 1221 | |||
| 1222 | if (err != CMD_OK) | ||
| 1223 | |||
| 1224 | ppp_error(card, err, mb); | ||
| 1225 | |||
| 1226 | else if (str) { | ||
| 1227 | |||
| 1228 | int len = mb->cmd.length; | ||
| 1229 | |||
| 1230 | memcpy(str, mb->data, len); | ||
| 1231 | str[len] = '\0'; | ||
| 1232 | |||
| 1233 | } | ||
| 1234 | |||
| 1235 | return err; | ||
| 1236 | } | ||
| 1237 | /*=========================================================================== | ||
| 1238 | * Set Out-Bound Authentication. | ||
| 1239 | */ | ||
| 1240 | static int ppp_set_outbnd_auth (sdla_t *card, ppp_private_area_t *ppp_priv_area) | ||
| 1241 | { | ||
| 1242 | ppp_mbox_t *mb = card->mbox; | ||
| 1243 | int err; | ||
| 1244 | |||
| 1245 | memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); | ||
| 1246 | memset(&mb->data, 0, (strlen(ppp_priv_area->userid) + | ||
| 1247 | strlen(ppp_priv_area->passwd) + 2 ) ); | ||
| 1248 | memcpy(mb->data, ppp_priv_area->userid, strlen(ppp_priv_area->userid)); | ||
| 1249 | memcpy((mb->data + strlen(ppp_priv_area->userid) + 1), | ||
| 1250 | ppp_priv_area->passwd, strlen(ppp_priv_area->passwd)); | ||
| 1251 | |||
| 1252 | mb->cmd.length = strlen(ppp_priv_area->userid) + | ||
| 1253 | strlen(ppp_priv_area->passwd) + 2 ; | ||
| 1254 | |||
| 1255 | mb->cmd.command = PPP_SET_OUTBOUND_AUTH; | ||
| 1256 | |||
| 1257 | err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; | ||
| 1258 | |||
| 1259 | if (err != CMD_OK) | ||
| 1260 | ppp_error(card, err, mb); | ||
| 1261 | |||
| 1262 | return err; | ||
| 1263 | } | ||
| 1264 | |||
| 1265 | /*=========================================================================== | ||
| 1266 | * Set In-Bound Authentication. | ||
| 1267 | */ | ||
| 1268 | static int ppp_set_inbnd_auth (sdla_t *card, ppp_private_area_t *ppp_priv_area) | ||
| 1269 | { | ||
| 1270 | ppp_mbox_t *mb = card->mbox; | ||
| 1271 | int err, i; | ||
| 1272 | char* user_tokens[32]; | ||
| 1273 | char* pass_tokens[32]; | ||
| 1274 | int userids, passwds; | ||
| 1275 | int add_ptr; | ||
| 1276 | |||
| 1277 | memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); | ||
| 1278 | memset(&mb->data, 0, 1008); | ||
| 1279 | memcpy(mb->data, ppp_priv_area->sysname, | ||
| 1280 | strlen(ppp_priv_area->sysname)); | ||
| 1281 | |||
| 1282 | /* Parse the userid string and the password string and build a string | ||
| 1283 | to copy it to the data area of the command structure. The string | ||
| 1284 | will look like "SYS_NAME<NULL>USER1<NULL>PASS1<NULL>USER2<NULL>PASS2 | ||
| 1285 | ....<NULL> " | ||
| 1286 | */ | ||
| 1287 | userids = tokenize( ppp_priv_area->userid, user_tokens); | ||
| 1288 | passwds = tokenize( ppp_priv_area->passwd, pass_tokens); | ||
| 1289 | |||
| 1290 | if (userids != passwds){ | ||
| 1291 | printk(KERN_INFO "%s: Number of passwords does not equal the number of user ids\n", card->devname); | ||
| 1292 | return 1; | ||
| 1293 | } | ||
| 1294 | |||
| 1295 | add_ptr = strlen(ppp_priv_area->sysname) + 1; | ||
| 1296 | for (i=0; i<userids; i++){ | ||
| 1297 | memcpy((mb->data + add_ptr), user_tokens[i], | ||
| 1298 | strlen(user_tokens[i])); | ||
| 1299 | memcpy((mb->data + add_ptr + strlen(user_tokens[i]) + 1), | ||
| 1300 | pass_tokens[i], strlen(pass_tokens[i])); | ||
| 1301 | add_ptr = add_ptr + strlen(user_tokens[i]) + 1 + | ||
| 1302 | strlen(pass_tokens[i]) + 1; | ||
| 1303 | } | ||
| 1304 | |||
| 1305 | mb->cmd.length = add_ptr + 1; | ||
| 1306 | mb->cmd.command = PPP_SET_INBOUND_AUTH; | ||
| 1307 | |||
| 1308 | err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; | ||
| 1309 | |||
| 1310 | if (err != CMD_OK) | ||
| 1311 | ppp_error(card, err, mb); | ||
| 1312 | |||
| 1313 | return err; | ||
| 1314 | } | ||
| 1315 | |||
| 1316 | |||
| 1317 | /*============================================================================ | ||
| 1318 | * Tokenize string. | ||
| 1319 | * Parse a string of the following syntax: | ||
| 1320 | * <arg1>,<arg2>,... | ||
| 1321 | * and fill array of tokens with pointers to string elements. | ||
| 1322 | * | ||
| 1323 | */ | ||
| 1324 | static int tokenize (char *str, char **tokens) | ||
| 1325 | { | ||
| 1326 | int cnt = 0; | ||
| 1327 | |||
| 1328 | tokens[0] = strsep(&str, "/"); | ||
| 1329 | while (tokens[cnt] && (cnt < 32 - 1)) | ||
| 1330 | { | ||
| 1331 | tokens[cnt] = strstrip(tokens[cnt], " \t"); | ||
| 1332 | tokens[++cnt] = strsep(&str, "/"); | ||
| 1333 | } | ||
| 1334 | return cnt; | ||
| 1335 | } | ||
| 1336 | |||
| 1337 | /*============================================================================ | ||
| 1338 | * Strip leading and trailing spaces off the string str. | ||
| 1339 | */ | ||
| 1340 | static char* strstrip (char *str, char* s) | ||
| 1341 | { | ||
| 1342 | char *eos = str + strlen(str); /* -> end of string */ | ||
| 1343 | |||
| 1344 | while (*str && strchr(s, *str)) | ||
| 1345 | ++str /* strip leading spaces */ | ||
| 1346 | ; | ||
| 1347 | while ((eos > str) && strchr(s, *(eos - 1))) | ||
| 1348 | --eos /* strip trailing spaces */ | ||
| 1349 | ; | ||
| 1350 | *eos = '\0'; | ||
| 1351 | return str; | ||
| 1352 | } | ||
| 1353 | /*============================================================================ | ||
| 1354 | * Configure PPP firmware. | ||
| 1355 | */ | ||
| 1356 | static int ppp_configure(sdla_t *card, void *data) | ||
| 1357 | { | ||
| 1358 | ppp_mbox_t *mb = card->mbox; | ||
| 1359 | int data_len = sizeof(ppp508_conf_t); | ||
| 1360 | int err; | ||
| 1361 | |||
| 1362 | memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); | ||
| 1363 | memcpy(mb->data, data, data_len); | ||
| 1364 | mb->cmd.length = data_len; | ||
| 1365 | mb->cmd.command = PPP_SET_CONFIG; | ||
| 1366 | err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; | ||
| 1367 | |||
| 1368 | if (err != CMD_OK) | ||
| 1369 | ppp_error(card, err, mb); | ||
| 1370 | |||
| 1371 | return err; | ||
| 1372 | } | ||
| 1373 | |||
| 1374 | /*============================================================================ | ||
| 1375 | * Set interrupt mode. | ||
| 1376 | */ | ||
| 1377 | static int ppp_set_intr_mode(sdla_t *card, unsigned char mode) | ||
| 1378 | { | ||
| 1379 | ppp_mbox_t *mb = card->mbox; | ||
| 1380 | ppp_intr_info_t *ppp_intr_data = (ppp_intr_info_t *) &mb->data[0]; | ||
| 1381 | int err; | ||
| 1382 | |||
| 1383 | memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); | ||
| 1384 | ppp_intr_data->i_enable = mode; | ||
| 1385 | |||
| 1386 | ppp_intr_data->irq = card->hw.irq; | ||
| 1387 | mb->cmd.length = 2; | ||
| 1388 | |||
| 1389 | /* If timer has been enabled, set the timer delay to 1sec */ | ||
| 1390 | if (mode & 0x80){ | ||
| 1391 | ppp_intr_data->timer_len = 250; //5;//100; //250; | ||
| 1392 | mb->cmd.length = 4; | ||
| 1393 | } | ||
| 1394 | |||
| 1395 | mb->cmd.command = PPP_SET_INTR_FLAGS; | ||
| 1396 | err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; | ||
| 1397 | |||
| 1398 | if (err != CMD_OK) | ||
| 1399 | ppp_error(card, err, mb); | ||
| 1400 | |||
| 1401 | |||
| 1402 | return err; | ||
| 1403 | } | ||
| 1404 | |||
| 1405 | /*============================================================================ | ||
| 1406 | * Enable communications. | ||
| 1407 | */ | ||
| 1408 | static int ppp_comm_enable(sdla_t *card) | ||
| 1409 | { | ||
| 1410 | ppp_mbox_t *mb = card->mbox; | ||
| 1411 | int err; | ||
| 1412 | |||
| 1413 | memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); | ||
| 1414 | mb->cmd.command = PPP_COMM_ENABLE; | ||
| 1415 | err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; | ||
| 1416 | |||
| 1417 | if (err != CMD_OK) | ||
| 1418 | ppp_error(card, err, mb); | ||
| 1419 | else | ||
| 1420 | card->u.p.comm_enabled = 1; | ||
| 1421 | |||
| 1422 | return err; | ||
| 1423 | } | ||
| 1424 | |||
| 1425 | /*============================================================================ | ||
| 1426 | * Disable communications. | ||
| 1427 | */ | ||
| 1428 | static int ppp_comm_disable(sdla_t *card) | ||
| 1429 | { | ||
| 1430 | ppp_mbox_t *mb = card->mbox; | ||
| 1431 | int err; | ||
| 1432 | |||
| 1433 | memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); | ||
| 1434 | mb->cmd.command = PPP_COMM_DISABLE; | ||
| 1435 | err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; | ||
| 1436 | if (err != CMD_OK) | ||
| 1437 | ppp_error(card, err, mb); | ||
| 1438 | else | ||
| 1439 | card->u.p.comm_enabled = 0; | ||
| 1440 | |||
| 1441 | return err; | ||
| 1442 | } | ||
| 1443 | |||
| 1444 | static int ppp_comm_disable_shutdown(sdla_t *card) | ||
| 1445 | { | ||
| 1446 | ppp_mbox_t *mb = card->mbox; | ||
| 1447 | ppp_intr_info_t *ppp_intr_data; | ||
| 1448 | int err; | ||
| 1449 | |||
| 1450 | if (!mb){ | ||
| 1451 | return 1; | ||
| 1452 | } | ||
| 1453 | |||
| 1454 | ppp_intr_data = (ppp_intr_info_t *) &mb->data[0]; | ||
| 1455 | |||
| 1456 | /* Disable all interrupts */ | ||
| 1457 | memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); | ||
| 1458 | ppp_intr_data->i_enable = 0; | ||
| 1459 | |||
| 1460 | ppp_intr_data->irq = card->hw.irq; | ||
| 1461 | mb->cmd.length = 2; | ||
| 1462 | |||
| 1463 | mb->cmd.command = PPP_SET_INTR_FLAGS; | ||
| 1464 | err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; | ||
| 1465 | |||
| 1466 | /* Disable communicatinons */ | ||
| 1467 | memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); | ||
| 1468 | mb->cmd.command = PPP_COMM_DISABLE; | ||
| 1469 | err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; | ||
| 1470 | |||
| 1471 | card->u.p.comm_enabled = 0; | ||
| 1472 | |||
| 1473 | return 0; | ||
| 1474 | } | ||
| 1475 | |||
| 1476 | |||
| 1477 | |||
| 1478 | /*============================================================================ | ||
| 1479 | * Get communications error statistics. | ||
| 1480 | */ | ||
| 1481 | static int ppp_get_err_stats(sdla_t *card) | ||
| 1482 | { | ||
| 1483 | ppp_mbox_t *mb = card->mbox; | ||
| 1484 | int err; | ||
| 1485 | |||
| 1486 | memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); | ||
| 1487 | mb->cmd.command = PPP_READ_ERROR_STATS; | ||
| 1488 | err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; | ||
| 1489 | |||
| 1490 | if (err == CMD_OK) { | ||
| 1491 | |||
| 1492 | ppp_err_stats_t* stats = (void*)mb->data; | ||
| 1493 | card->wandev.stats.rx_over_errors = stats->rx_overrun; | ||
| 1494 | card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; | ||
| 1495 | card->wandev.stats.rx_missed_errors = stats->rx_abort; | ||
| 1496 | card->wandev.stats.rx_length_errors = stats->rx_lost; | ||
| 1497 | card->wandev.stats.tx_aborted_errors = stats->tx_abort; | ||
| 1498 | |||
| 1499 | } else | ||
| 1500 | ppp_error(card, err, mb); | ||
| 1501 | |||
| 1502 | return err; | ||
| 1503 | } | ||
| 1504 | |||
| 1505 | /*============================================================================ | ||
| 1506 | * Send packet. | ||
| 1507 | * Return: 0 - o.k. | ||
| 1508 | * 1 - no transmit buffers available | ||
| 1509 | */ | ||
| 1510 | static int ppp_send (sdla_t *card, void *data, unsigned len, unsigned proto) | ||
| 1511 | { | ||
| 1512 | ppp_buf_ctl_t *txbuf = card->u.p.txbuf; | ||
| 1513 | |||
| 1514 | if (txbuf->flag) | ||
| 1515 | return 1; | ||
| 1516 | |||
| 1517 | sdla_poke(&card->hw, txbuf->buf.ptr, data, len); | ||
| 1518 | |||
| 1519 | txbuf->length = len; /* frame length */ | ||
| 1520 | |||
| 1521 | if (proto == htons(ETH_P_IPX)) | ||
| 1522 | txbuf->proto = 0x01; /* protocol ID */ | ||
| 1523 | else | ||
| 1524 | txbuf->proto = 0x00; /* protocol ID */ | ||
| 1525 | |||
| 1526 | txbuf->flag = 1; /* start transmission */ | ||
| 1527 | |||
| 1528 | /* Update transmit buffer control fields */ | ||
| 1529 | card->u.p.txbuf = ++txbuf; | ||
| 1530 | |||
| 1531 | if ((void*)txbuf > card->u.p.txbuf_last) | ||
| 1532 | card->u.p.txbuf = card->u.p.txbuf_base; | ||
| 1533 | |||
| 1534 | return 0; | ||
| 1535 | } | ||
| 1536 | |||
| 1537 | /****** Firmware Error Handler **********************************************/ | ||
| 1538 | |||
| 1539 | /*============================================================================ | ||
| 1540 | * Firmware error handler. | ||
| 1541 | * This routine is called whenever firmware command returns non-zero | ||
| 1542 | * return code. | ||
| 1543 | * | ||
| 1544 | * Return zero if previous command has to be cancelled. | ||
| 1545 | */ | ||
| 1546 | static int ppp_error(sdla_t *card, int err, ppp_mbox_t *mb) | ||
| 1547 | { | ||
| 1548 | unsigned cmd = mb->cmd.command; | ||
| 1549 | |||
| 1550 | switch (err) { | ||
| 1551 | |||
| 1552 | case CMD_TIMEOUT: | ||
| 1553 | printk(KERN_ERR "%s: command 0x%02X timed out!\n", | ||
| 1554 | card->devname, cmd); | ||
| 1555 | break; | ||
| 1556 | |||
| 1557 | default: | ||
| 1558 | printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" | ||
| 1559 | , card->devname, cmd, err); | ||
| 1560 | } | ||
| 1561 | |||
| 1562 | return 0; | ||
| 1563 | } | ||
| 1564 | |||
| 1565 | /****** Interrupt Handlers **************************************************/ | ||
| 1566 | |||
| 1567 | /*============================================================================ | ||
| 1568 | * PPP interrupt service routine. | ||
| 1569 | */ | ||
| 1570 | static void wpp_isr (sdla_t *card) | ||
| 1571 | { | ||
| 1572 | ppp_flags_t *flags = card->flags; | ||
| 1573 | char *ptr = &flags->iflag; | ||
| 1574 | struct net_device *dev = card->wandev.dev; | ||
| 1575 | int i; | ||
| 1576 | |||
| 1577 | card->in_isr = 1; | ||
| 1578 | ++card->statistics.isr_entry; | ||
| 1579 | |||
| 1580 | if (!dev && flags->iflag != PPP_INTR_CMD){ | ||
| 1581 | card->in_isr = 0; | ||
| 1582 | flags->iflag = 0; | ||
| 1583 | return; | ||
| 1584 | } | ||
| 1585 | |||
| 1586 | if (test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { | ||
| 1587 | card->in_isr = 0; | ||
| 1588 | flags->iflag = 0; | ||
| 1589 | return; | ||
| 1590 | } | ||
| 1591 | |||
| 1592 | |||
| 1593 | if(card->hw.type != SDLA_S514){ | ||
| 1594 | if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)) { | ||
| 1595 | ++card->statistics.isr_already_critical; | ||
| 1596 | printk (KERN_INFO "%s: Critical while in ISR!\n", | ||
| 1597 | card->devname); | ||
| 1598 | card->in_isr = 0; | ||
| 1599 | flags->iflag = 0; | ||
| 1600 | return; | ||
| 1601 | } | ||
| 1602 | } | ||
| 1603 | |||
| 1604 | switch (flags->iflag) { | ||
| 1605 | |||
| 1606 | case PPP_INTR_RXRDY: /* receive interrupt 0x01 (bit 0)*/ | ||
| 1607 | ++card->statistics.isr_rx; | ||
| 1608 | rx_intr(card); | ||
| 1609 | break; | ||
| 1610 | |||
| 1611 | case PPP_INTR_TXRDY: /* transmit interrupt 0x02 (bit 1)*/ | ||
| 1612 | ++card->statistics.isr_tx; | ||
| 1613 | flags->imask &= ~PPP_INTR_TXRDY; | ||
| 1614 | netif_wake_queue(dev); | ||
| 1615 | break; | ||
| 1616 | |||
| 1617 | case PPP_INTR_CMD: /* interface command completed */ | ||
| 1618 | ++Intr_test_counter; | ||
| 1619 | ++card->statistics.isr_intr_test; | ||
| 1620 | break; | ||
| 1621 | |||
| 1622 | case PPP_INTR_MODEM: /* modem status change (DCD, CTS) 0x04 (bit 2)*/ | ||
| 1623 | case PPP_INTR_DISC: /* Data link disconnected 0x10 (bit 4)*/ | ||
| 1624 | case PPP_INTR_OPEN: /* Data link open 0x20 (bit 5)*/ | ||
| 1625 | case PPP_INTR_DROP_DTR: /* DTR drop timeout expired 0x40 bit 6 */ | ||
| 1626 | event_intr(card); | ||
| 1627 | break; | ||
| 1628 | |||
| 1629 | case PPP_INTR_TIMER: | ||
| 1630 | timer_intr(card); | ||
| 1631 | break; | ||
| 1632 | |||
| 1633 | default: /* unexpected interrupt */ | ||
| 1634 | ++card->statistics.isr_spurious; | ||
| 1635 | printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", | ||
| 1636 | card->devname, flags->iflag); | ||
| 1637 | printk(KERN_INFO "%s: ID Bytes = ",card->devname); | ||
| 1638 | for(i = 0; i < 8; i ++) | ||
| 1639 | printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); | ||
| 1640 | printk(KERN_INFO "\n"); | ||
| 1641 | } | ||
| 1642 | |||
| 1643 | card->in_isr = 0; | ||
| 1644 | flags->iflag = 0; | ||
| 1645 | return; | ||
| 1646 | } | ||
| 1647 | |||
| 1648 | /*============================================================================ | ||
| 1649 | * Receive interrupt handler. | ||
| 1650 | */ | ||
| 1651 | static void rx_intr(sdla_t *card) | ||
| 1652 | { | ||
| 1653 | ppp_buf_ctl_t *rxbuf = card->rxmb; | ||
| 1654 | struct net_device *dev = card->wandev.dev; | ||
| 1655 | ppp_private_area_t *ppp_priv_area; | ||
| 1656 | struct sk_buff *skb; | ||
| 1657 | unsigned len; | ||
| 1658 | void *buf; | ||
| 1659 | int i; | ||
| 1660 | ppp_flags_t *flags = card->flags; | ||
| 1661 | char *ptr = &flags->iflag; | ||
| 1662 | int udp_type; | ||
| 1663 | |||
| 1664 | |||
| 1665 | if (rxbuf->flag != 0x01) { | ||
| 1666 | |||
| 1667 | printk(KERN_INFO | ||
| 1668 | "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", | ||
| 1669 | card->devname, (unsigned)rxbuf, rxbuf->flag); | ||
| 1670 | |||
| 1671 | printk(KERN_INFO "%s: ID Bytes = ",card->devname); | ||
| 1672 | |||
| 1673 | for(i = 0; i < 8; i ++) | ||
| 1674 | printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); | ||
| 1675 | printk(KERN_INFO "\n"); | ||
| 1676 | |||
| 1677 | ++card->statistics.rx_intr_corrupt_rx_bfr; | ||
| 1678 | |||
| 1679 | |||
| 1680 | /* Bug Fix: Mar 6 2000 | ||
| 1681 | * If we get a corrupted mailbox, it means that driver | ||
| 1682 | * is out of sync with the firmware. There is no recovery. | ||
| 1683 | * If we don't turn off all interrupts for this card | ||
| 1684 | * the machine will crash. | ||
| 1685 | */ | ||
| 1686 | printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); | ||
| 1687 | printk(KERN_INFO "Please contact Sangoma Technologies !\n"); | ||
| 1688 | ppp_set_intr_mode(card,0); | ||
| 1689 | return; | ||
| 1690 | } | ||
| 1691 | |||
| 1692 | if (dev && netif_running(dev) && dev->priv){ | ||
| 1693 | |||
| 1694 | len = rxbuf->length; | ||
| 1695 | ppp_priv_area = dev->priv; | ||
| 1696 | |||
| 1697 | /* Allocate socket buffer */ | ||
| 1698 | skb = dev_alloc_skb(len); | ||
| 1699 | |||
| 1700 | if (skb != NULL) { | ||
| 1701 | |||
| 1702 | /* Copy data to the socket buffer */ | ||
| 1703 | unsigned addr = rxbuf->buf.ptr; | ||
| 1704 | |||
| 1705 | if ((addr + len) > card->u.p.rx_top + 1) { | ||
| 1706 | |||
| 1707 | unsigned tmp = card->u.p.rx_top - addr + 1; | ||
| 1708 | buf = skb_put(skb, tmp); | ||
| 1709 | sdla_peek(&card->hw, addr, buf, tmp); | ||
| 1710 | addr = card->u.p.rx_base; | ||
| 1711 | len -= tmp; | ||
| 1712 | } | ||
| 1713 | buf = skb_put(skb, len); | ||
| 1714 | sdla_peek(&card->hw, addr, buf, len); | ||
| 1715 | |||
| 1716 | /* Decapsulate packet */ | ||
| 1717 | switch (rxbuf->proto) { | ||
| 1718 | |||
| 1719 | case 0x00: | ||
| 1720 | skb->protocol = htons(ETH_P_IP); | ||
| 1721 | break; | ||
| 1722 | |||
| 1723 | case 0x01: | ||
| 1724 | skb->protocol = htons(ETH_P_IPX); | ||
| 1725 | break; | ||
| 1726 | } | ||
| 1727 | |||
| 1728 | udp_type = udp_pkt_type( skb, card ); | ||
| 1729 | |||
| 1730 | if (udp_type == UDP_PTPIPE_TYPE){ | ||
| 1731 | |||
| 1732 | /* Handle a UDP Request in Timer Interrupt */ | ||
| 1733 | if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, card, skb, dev, | ||
| 1734 | ppp_priv_area)){ | ||
| 1735 | flags->imask |= PPP_INTR_TIMER; | ||
| 1736 | } | ||
| 1737 | ++ppp_priv_area->rx_intr_stat.rx_intr_PIPE_request; | ||
| 1738 | |||
| 1739 | |||
| 1740 | } else if (handle_IPXWAN(skb->data,card->devname, | ||
| 1741 | ppp_priv_area->enable_IPX, | ||
| 1742 | ppp_priv_area->network_number, | ||
| 1743 | skb->protocol)) { | ||
| 1744 | |||
| 1745 | /* Handle an IPXWAN packet */ | ||
| 1746 | if( ppp_priv_area->enable_IPX) { | ||
| 1747 | |||
| 1748 | /* Make sure we are not already sending */ | ||
| 1749 | if (!test_bit(SEND_CRIT, &card->wandev.critical)){ | ||
| 1750 | ppp_send(card, skb->data, skb->len, htons(ETH_P_IPX)); | ||
| 1751 | } | ||
| 1752 | dev_kfree_skb_any(skb); | ||
| 1753 | |||
| 1754 | } else { | ||
| 1755 | ++card->wandev.stats.rx_dropped; | ||
| 1756 | } | ||
| 1757 | } else { | ||
| 1758 | /* Pass data up the protocol stack */ | ||
| 1759 | skb->dev = dev; | ||
| 1760 | skb->mac.raw = skb->data; | ||
| 1761 | |||
| 1762 | ++card->wandev.stats.rx_packets; | ||
| 1763 | card->wandev.stats.rx_bytes += skb->len; | ||
| 1764 | ++ppp_priv_area->rx_intr_stat.rx_intr_bfr_passed_to_stack; | ||
| 1765 | netif_rx(skb); | ||
| 1766 | dev->last_rx = jiffies; | ||
| 1767 | } | ||
| 1768 | |||
| 1769 | } else { | ||
| 1770 | |||
| 1771 | if (net_ratelimit()){ | ||
| 1772 | printk(KERN_INFO "%s: no socket buffers available!\n", | ||
| 1773 | card->devname); | ||
| 1774 | } | ||
| 1775 | ++card->wandev.stats.rx_dropped; | ||
| 1776 | ++ppp_priv_area->rx_intr_stat.rx_intr_no_socket; | ||
| 1777 | } | ||
| 1778 | |||
| 1779 | } else { | ||
| 1780 | ++card->statistics.rx_intr_dev_not_started; | ||
| 1781 | } | ||
| 1782 | |||
| 1783 | /* Release buffer element and calculate a pointer to the next one */ | ||
| 1784 | rxbuf->flag = 0x00; | ||
| 1785 | card->rxmb = ++rxbuf; | ||
| 1786 | if ((void*)rxbuf > card->u.p.rxbuf_last) | ||
| 1787 | card->rxmb = card->u.p.rxbuf_base; | ||
| 1788 | } | ||
| 1789 | |||
| 1790 | |||
| 1791 | void event_intr (sdla_t *card) | ||
| 1792 | { | ||
| 1793 | |||
| 1794 | struct net_device* dev = card->wandev.dev; | ||
| 1795 | ppp_private_area_t* ppp_priv_area = dev->priv; | ||
| 1796 | volatile ppp_flags_t *flags = card->flags; | ||
| 1797 | |||
| 1798 | switch (flags->iflag){ | ||
| 1799 | |||
| 1800 | case PPP_INTR_MODEM: /* modem status change (DCD, CTS) 0x04 (bit 2)*/ | ||
| 1801 | |||
| 1802 | if (net_ratelimit()){ | ||
| 1803 | printk (KERN_INFO "%s: Modem status: DCD=%s CTS=%s\n", | ||
| 1804 | card->devname, DCD(flags->mstatus), CTS(flags->mstatus)); | ||
| 1805 | } | ||
| 1806 | break; | ||
| 1807 | |||
| 1808 | case PPP_INTR_DISC: /* Data link disconnected 0x10 (bit 4)*/ | ||
| 1809 | |||
| 1810 | NEX_PRINTK (KERN_INFO "Data link disconnected intr Cause %X\n", | ||
| 1811 | flags->disc_cause); | ||
| 1812 | |||
| 1813 | if (flags->disc_cause & | ||
| 1814 | (PPP_LOCAL_TERMINATION | PPP_DCD_CTS_DROP | | ||
| 1815 | PPP_REMOTE_TERMINATION)) { | ||
| 1816 | |||
| 1817 | if (card->u.p.ip_mode == WANOPT_PPP_PEER) { | ||
| 1818 | set_bit(0,&Read_connection_info); | ||
| 1819 | } | ||
| 1820 | wanpipe_set_state(card, WAN_DISCONNECTED); | ||
| 1821 | |||
| 1822 | show_disc_cause(card, flags->disc_cause); | ||
| 1823 | ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT; | ||
| 1824 | flags->imask |= PPP_INTR_TIMER; | ||
| 1825 | trigger_ppp_poll(dev); | ||
| 1826 | } | ||
| 1827 | break; | ||
| 1828 | |||
| 1829 | case PPP_INTR_OPEN: /* Data link open 0x20 (bit 5)*/ | ||
| 1830 | |||
| 1831 | NEX_PRINTK (KERN_INFO "%s: PPP Link Open, LCP=%s IP=%s\n", | ||
| 1832 | card->devname,LCP(flags->lcp_state), | ||
| 1833 | IP(flags->ip_state)); | ||
| 1834 | |||
| 1835 | if (flags->lcp_state == 0x09 && | ||
| 1836 | (flags->ip_state == 0x09 || flags->ipx_state == 0x09)){ | ||
| 1837 | |||
| 1838 | /* Initialize the polling timer and set the state | ||
| 1839 | * to WAN_CONNNECTED */ | ||
| 1840 | |||
| 1841 | |||
| 1842 | /* BUG FIX: When the protocol restarts, during heavy | ||
| 1843 | * traffic, board tx buffers and driver tx buffers | ||
| 1844 | * can go out of sync. This checks the condition | ||
| 1845 | * and if the tx buffers are out of sync, the | ||
| 1846 | * protocols are restarted. | ||
| 1847 | * I don't know why the board tx buffer is out | ||
| 1848 | * of sync. It could be that a packets is tx | ||
| 1849 | * while the link is down, but that is not | ||
| 1850 | * possible. The other possiblility is that the | ||
| 1851 | * firmware doesn't reinitialize properly. | ||
| 1852 | * FIXME: A better fix should be found. | ||
| 1853 | */ | ||
| 1854 | if (detect_and_fix_tx_bug(card)){ | ||
| 1855 | |||
| 1856 | ppp_comm_disable(card); | ||
| 1857 | |||
| 1858 | wanpipe_set_state(card, WAN_DISCONNECTED); | ||
| 1859 | |||
| 1860 | ppp_priv_area->timer_int_enabled |= | ||
| 1861 | TMR_INT_ENABLED_PPP_EVENT; | ||
| 1862 | flags->imask |= PPP_INTR_TIMER; | ||
| 1863 | break; | ||
| 1864 | } | ||
| 1865 | |||
| 1866 | card->state_tick = jiffies; | ||
| 1867 | wanpipe_set_state(card, WAN_CONNECTED); | ||
| 1868 | |||
| 1869 | NEX_PRINTK(KERN_INFO "CON: L Tx: %lx B Tx: %lx || L Rx %lx B Rx %lx\n", | ||
| 1870 | (unsigned long)card->u.p.txbuf, *card->u.p.txbuf_next, | ||
| 1871 | (unsigned long)card->rxmb, *card->u.p.rxbuf_next); | ||
| 1872 | |||
| 1873 | /* Tell timer interrupt that PPP event occurred */ | ||
| 1874 | ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT; | ||
| 1875 | flags->imask |= PPP_INTR_TIMER; | ||
| 1876 | |||
| 1877 | /* If we are in PEER mode, we must first obtain the | ||
| 1878 | * IP information and then go into the poll routine */ | ||
| 1879 | if (card->u.p.ip_mode != WANOPT_PPP_PEER){ | ||
| 1880 | trigger_ppp_poll(dev); | ||
| 1881 | } | ||
| 1882 | } | ||
| 1883 | break; | ||
| 1884 | |||
| 1885 | case PPP_INTR_DROP_DTR: /* DTR drop timeout expired 0x40 bit 6 */ | ||
| 1886 | |||
| 1887 | NEX_PRINTK(KERN_INFO "DTR Drop Timeout Interrrupt \n"); | ||
| 1888 | |||
| 1889 | if (card->u.p.ip_mode == WANOPT_PPP_PEER) { | ||
| 1890 | set_bit(0,&Read_connection_info); | ||
| 1891 | } | ||
| 1892 | |||
| 1893 | wanpipe_set_state(card, WAN_DISCONNECTED); | ||
| 1894 | |||
| 1895 | show_disc_cause(card, flags->disc_cause); | ||
| 1896 | ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT; | ||
| 1897 | flags->imask |= PPP_INTR_TIMER; | ||
| 1898 | trigger_ppp_poll(dev); | ||
| 1899 | break; | ||
| 1900 | |||
| 1901 | default: | ||
| 1902 | printk(KERN_INFO "%s: Error, Invalid PPP Event\n",card->devname); | ||
| 1903 | } | ||
| 1904 | } | ||
| 1905 | |||
| 1906 | |||
| 1907 | |||
| 1908 | /* TIMER INTERRUPT */ | ||
| 1909 | |||
| 1910 | void timer_intr (sdla_t *card) | ||
| 1911 | { | ||
| 1912 | |||
| 1913 | struct net_device* dev = card->wandev.dev; | ||
| 1914 | ppp_private_area_t* ppp_priv_area = dev->priv; | ||
| 1915 | ppp_flags_t *flags = card->flags; | ||
| 1916 | |||
| 1917 | |||
| 1918 | if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG){ | ||
| 1919 | if (!config_ppp(card)){ | ||
| 1920 | ppp_priv_area->timer_int_enabled &= | ||
| 1921 | ~TMR_INT_ENABLED_CONFIG; | ||
| 1922 | } | ||
| 1923 | } | ||
| 1924 | |||
| 1925 | /* Update statistics */ | ||
| 1926 | if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE){ | ||
| 1927 | ppp_get_err_stats(card); | ||
| 1928 | if(!(--ppp_priv_area->update_comms_stats)){ | ||
| 1929 | ppp_priv_area->timer_int_enabled &= | ||
| 1930 | ~TMR_INT_ENABLED_UPDATE; | ||
| 1931 | } | ||
| 1932 | } | ||
| 1933 | |||
| 1934 | /* PPIPEMON UDP request */ | ||
| 1935 | |||
| 1936 | if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP){ | ||
| 1937 | process_udp_mgmt_pkt(card,dev, ppp_priv_area); | ||
| 1938 | ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP; | ||
| 1939 | } | ||
| 1940 | |||
| 1941 | /* PPP Event */ | ||
| 1942 | if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_PPP_EVENT){ | ||
| 1943 | |||
| 1944 | if (card->wandev.state == WAN_DISCONNECTED){ | ||
| 1945 | retrigger_comm(card); | ||
| 1946 | } | ||
| 1947 | |||
| 1948 | /* If the state is CONNECTING, it means that communicatins were | ||
| 1949 | * enabled. When the remote side enables its comminication we | ||
| 1950 | * should get an interrupt PPP_INTR_OPEN, thus turn off polling | ||
| 1951 | */ | ||
| 1952 | |||
| 1953 | else if (card->wandev.state == WAN_CONNECTING){ | ||
| 1954 | /* Turn off the timer interrupt */ | ||
| 1955 | ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_PPP_EVENT; | ||
| 1956 | } | ||
| 1957 | |||
| 1958 | /* If state is connected and we are in PEER mode | ||
| 1959 | * poll for an IP address which will be provided by remote end. | ||
| 1960 | */ | ||
| 1961 | else if ((card->wandev.state == WAN_CONNECTED && | ||
| 1962 | card->u.p.ip_mode == WANOPT_PPP_PEER) && | ||
| 1963 | test_bit(0,&Read_connection_info)){ | ||
| 1964 | |||
| 1965 | card->state_tick = jiffies; | ||
| 1966 | if (read_connection_info (card)){ | ||
| 1967 | printk(KERN_INFO "%s: Failed to read PEER IP Addresses\n", | ||
| 1968 | card->devname); | ||
| 1969 | }else{ | ||
| 1970 | clear_bit(0,&Read_connection_info); | ||
| 1971 | set_bit(1,&Read_connection_info); | ||
| 1972 | trigger_ppp_poll(dev); | ||
| 1973 | } | ||
| 1974 | }else{ | ||
| 1975 | //FIXME Put the comment back int | ||
| 1976 | ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_PPP_EVENT; | ||
| 1977 | } | ||
| 1978 | |||
| 1979 | }/* End of PPP_EVENT */ | ||
| 1980 | |||
| 1981 | |||
| 1982 | /* Only disable the timer interrupt if there are no udp, statistic */ | ||
| 1983 | /* updates or events pending */ | ||
| 1984 | if(!ppp_priv_area->timer_int_enabled) { | ||
| 1985 | flags->imask &= ~PPP_INTR_TIMER; | ||
| 1986 | } | ||
| 1987 | } | ||
| 1988 | |||
| 1989 | |||
| 1990 | static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto) | ||
| 1991 | { | ||
| 1992 | int i; | ||
| 1993 | |||
| 1994 | if( proto == htons(ETH_P_IPX) ) { | ||
| 1995 | //It's an IPX packet | ||
| 1996 | if(!enable_IPX) { | ||
| 1997 | //Return 1 so we don't pass it up the stack. | ||
| 1998 | return 1; | ||
| 1999 | } | ||
| 2000 | } else { | ||
| 2001 | //It's not IPX so pass it up the stack. | ||
| 2002 | return 0; | ||
| 2003 | } | ||
| 2004 | |||
| 2005 | if( sendpacket[16] == 0x90 && | ||
| 2006 | sendpacket[17] == 0x04) | ||
| 2007 | { | ||
| 2008 | //It's IPXWAN | ||
| 2009 | |||
| 2010 | if( sendpacket[2] == 0x02 && | ||
| 2011 | sendpacket[34] == 0x00) | ||
| 2012 | { | ||
| 2013 | //It's a timer request packet | ||
| 2014 | printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); | ||
| 2015 | |||
| 2016 | //Go through the routing options and answer no to every | ||
| 2017 | //option except Unnumbered RIP/SAP | ||
| 2018 | for(i = 41; sendpacket[i] == 0x00; i += 5) | ||
| 2019 | { | ||
| 2020 | //0x02 is the option for Unnumbered RIP/SAP | ||
| 2021 | if( sendpacket[i + 4] != 0x02) | ||
| 2022 | { | ||
| 2023 | sendpacket[i + 1] = 0; | ||
| 2024 | } | ||
| 2025 | } | ||
| 2026 | |||
| 2027 | //Skip over the extended Node ID option | ||
| 2028 | if( sendpacket[i] == 0x04 ) | ||
| 2029 | { | ||
| 2030 | i += 8; | ||
| 2031 | } | ||
| 2032 | |||
| 2033 | //We also want to turn off all header compression opt. | ||
| 2034 | for(; sendpacket[i] == 0x80 ;) | ||
| 2035 | { | ||
| 2036 | sendpacket[i + 1] = 0; | ||
| 2037 | i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; | ||
| 2038 | } | ||
| 2039 | |||
| 2040 | //Set the packet type to timer response | ||
| 2041 | sendpacket[34] = 0x01; | ||
| 2042 | |||
| 2043 | printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname); | ||
| 2044 | } | ||
| 2045 | else if( sendpacket[34] == 0x02 ) | ||
| 2046 | { | ||
| 2047 | //This is an information request packet | ||
| 2048 | printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname); | ||
| 2049 | |||
| 2050 | //Set the packet type to information response | ||
| 2051 | sendpacket[34] = 0x03; | ||
| 2052 | |||
| 2053 | //Set the router name | ||
| 2054 | sendpacket[51] = 'P'; | ||
| 2055 | sendpacket[52] = 'T'; | ||
| 2056 | sendpacket[53] = 'P'; | ||
| 2057 | sendpacket[54] = 'I'; | ||
| 2058 | sendpacket[55] = 'P'; | ||
| 2059 | sendpacket[56] = 'E'; | ||
| 2060 | sendpacket[57] = '-'; | ||
| 2061 | sendpacket[58] = CVHexToAscii(network_number >> 28); | ||
| 2062 | sendpacket[59] = CVHexToAscii((network_number & 0x0F000000)>> 24); | ||
| 2063 | sendpacket[60] = CVHexToAscii((network_number & 0x00F00000)>> 20); | ||
| 2064 | sendpacket[61] = CVHexToAscii((network_number & 0x000F0000)>> 16); | ||
| 2065 | sendpacket[62] = CVHexToAscii((network_number & 0x0000F000)>> 12); | ||
| 2066 | sendpacket[63] = CVHexToAscii((network_number & 0x00000F00)>> 8); | ||
| 2067 | sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4); | ||
| 2068 | sendpacket[65] = CVHexToAscii(network_number & 0x0000000F); | ||
| 2069 | for(i = 66; i < 99; i+= 1) | ||
| 2070 | { | ||
| 2071 | sendpacket[i] = 0; | ||
| 2072 | } | ||
| 2073 | |||
| 2074 | printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); | ||
| 2075 | } | ||
| 2076 | else | ||
| 2077 | { | ||
| 2078 | printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); | ||
| 2079 | return 0; | ||
| 2080 | } | ||
| 2081 | |||
| 2082 | //Set the WNodeID to our network address | ||
| 2083 | sendpacket[35] = (unsigned char)(network_number >> 24); | ||
| 2084 | sendpacket[36] = (unsigned char)((network_number & 0x00FF0000) >> 16); | ||
| 2085 | sendpacket[37] = (unsigned char)((network_number & 0x0000FF00) >> 8); | ||
| 2086 | sendpacket[38] = (unsigned char)(network_number & 0x000000FF); | ||
| 2087 | |||
| 2088 | return 1; | ||
| 2089 | } else { | ||
| 2090 | //If we get here it's an IPX-data packet, so it'll get passed up the stack. | ||
| 2091 | |||
| 2092 | //switch the network numbers | ||
| 2093 | switch_net_numbers(sendpacket, network_number, 1); | ||
| 2094 | return 0; | ||
| 2095 | } | ||
| 2096 | } | ||
| 2097 | |||
| 2098 | /****** Background Polling Routines ****************************************/ | ||
| 2099 | |||
| 2100 | /* All polling functions are invoked by the TIMER interrupt in the wpp_isr | ||
| 2101 | * routine. | ||
| 2102 | */ | ||
| 2103 | |||
| 2104 | /*============================================================================ | ||
| 2105 | * Monitor active link phase. | ||
| 2106 | */ | ||
| 2107 | static void process_route (sdla_t *card) | ||
| 2108 | { | ||
| 2109 | ppp_flags_t *flags = card->flags; | ||
| 2110 | struct net_device *dev = card->wandev.dev; | ||
| 2111 | ppp_private_area_t *ppp_priv_area = dev->priv; | ||
| 2112 | |||
| 2113 | if ((card->u.p.ip_mode == WANOPT_PPP_PEER) && | ||
| 2114 | (flags->ip_state == 0x09)){ | ||
| 2115 | |||
| 2116 | /* We get ip_local from the firmware in PEER mode. | ||
| 2117 | * Therefore, if ip_local is 0, we failed to obtain | ||
| 2118 | * the remote IP address. */ | ||
| 2119 | if (ppp_priv_area->ip_local == 0) | ||
| 2120 | return; | ||
| 2121 | |||
| 2122 | printk(KERN_INFO "%s: IPCP State Opened.\n", card->devname); | ||
| 2123 | if (read_info( card )) { | ||
| 2124 | printk(KERN_INFO | ||
| 2125 | "%s: An error occurred in IP assignment.\n", | ||
| 2126 | card->devname); | ||
| 2127 | } else { | ||
| 2128 | struct in_device *in_dev = dev->ip_ptr; | ||
| 2129 | if (in_dev != NULL ) { | ||
| 2130 | struct in_ifaddr *ifa = in_dev->ifa_list; | ||
| 2131 | |||
| 2132 | printk(KERN_INFO "%s: Assigned Lcl. Addr: %u.%u.%u.%u\n", | ||
| 2133 | card->devname, NIPQUAD(ifa->ifa_local)); | ||
| 2134 | printk(KERN_INFO "%s: Assigned Rmt. Addr: %u.%u.%u.%u\n", | ||
| 2135 | card->devname, NIPQUAD(ifa->ifa_address)); | ||
| 2136 | }else{ | ||
| 2137 | printk(KERN_INFO | ||
| 2138 | "%s: Error: Failed to add a route for PPP interface %s\n", | ||
| 2139 | card->devname,dev->name); | ||
| 2140 | } | ||
| 2141 | } | ||
| 2142 | } | ||
| 2143 | } | ||
| 2144 | |||
| 2145 | /*============================================================================ | ||
| 2146 | * Monitor physical link disconnected phase. | ||
| 2147 | * o if interface is up and the hold-down timeout has expired, then retry | ||
| 2148 | * connection. | ||
| 2149 | */ | ||
| 2150 | static void retrigger_comm(sdla_t *card) | ||
| 2151 | { | ||
| 2152 | struct net_device *dev = card->wandev.dev; | ||
| 2153 | |||
| 2154 | if (dev && ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) { | ||
| 2155 | |||
| 2156 | wanpipe_set_state(card, WAN_CONNECTING); | ||
| 2157 | |||
| 2158 | if(ppp_comm_enable(card) == CMD_OK){ | ||
| 2159 | init_ppp_tx_rx_buff( card ); | ||
| 2160 | } | ||
| 2161 | } | ||
| 2162 | } | ||
| 2163 | |||
| 2164 | /****** Miscellaneous Functions *********************************************/ | ||
| 2165 | |||
| 2166 | /*============================================================================ | ||
| 2167 | * Configure S508 adapter. | ||
| 2168 | */ | ||
| 2169 | static int config508(struct net_device *dev, sdla_t *card) | ||
| 2170 | { | ||
| 2171 | ppp508_conf_t cfg; | ||
| 2172 | struct in_device *in_dev = dev->ip_ptr; | ||
| 2173 | ppp_private_area_t *ppp_priv_area = dev->priv; | ||
| 2174 | |||
| 2175 | /* Prepare PPP configuration structure */ | ||
| 2176 | memset(&cfg, 0, sizeof(ppp508_conf_t)); | ||
| 2177 | |||
| 2178 | if (card->wandev.clocking) | ||
| 2179 | cfg.line_speed = card->wandev.bps; | ||
| 2180 | |||
| 2181 | if (card->wandev.interface == WANOPT_RS232) | ||
| 2182 | cfg.conf_flags |= INTERFACE_LEVEL_RS232; | ||
| 2183 | |||
| 2184 | |||
| 2185 | cfg.conf_flags |= DONT_TERMINATE_LNK_MAX_CONFIG; /*send Configure-Request packets forever*/ | ||
| 2186 | cfg.txbuf_percent = PERCENT_TX_BUFF; /* % of Tx bufs */ | ||
| 2187 | cfg.mtu_local = card->wandev.mtu; | ||
| 2188 | cfg.mtu_remote = card->wandev.mtu; /* Default */ | ||
| 2189 | cfg.restart_tmr = TIME_BETWEEN_CONF_REQ; /* 30 = 3sec */ | ||
| 2190 | cfg.auth_rsrt_tmr = TIME_BETWEEN_PAP_CHAP_REQ; /* 30 = 3sec */ | ||
| 2191 | cfg.auth_wait_tmr = WAIT_PAP_CHAP_WITHOUT_REPLY; /* 300 = 30s */ | ||
| 2192 | cfg.mdm_fail_tmr = WAIT_AFTER_DCD_CTS_LOW; /* 5 = 0.5s */ | ||
| 2193 | cfg.dtr_drop_tmr = TIME_DCD_CTS_LOW_AFTER_LNK_DOWN; /* 10 = 1s */ | ||
| 2194 | cfg.connect_tmout = WAIT_DCD_HIGH_AFTER_ENABLE_COMM; /* 900 = 90s */ | ||
| 2195 | cfg.conf_retry = MAX_CONF_REQ_WITHOUT_REPLY; /* 10 = 1s */ | ||
| 2196 | cfg.term_retry = MAX_TERM_REQ_WITHOUT_REPLY; /* 2 times */ | ||
| 2197 | cfg.fail_retry = NUM_CONF_NAK_WITHOUT_REPLY; /* 5 times */ | ||
| 2198 | cfg.auth_retry = NUM_AUTH_REQ_WITHOUT_REPLY; /* 10 times */ | ||
| 2199 | |||
| 2200 | |||
| 2201 | if( !card->u.p.authenticator ) { | ||
| 2202 | printk(KERN_INFO "%s: Device is not configured as an authenticator\n", | ||
| 2203 | card->devname); | ||
| 2204 | cfg.auth_options = NO_AUTHENTICATION; | ||
| 2205 | }else{ | ||
| 2206 | printk(KERN_INFO "%s: Device is configured as an authenticator\n", | ||
| 2207 | card->devname); | ||
| 2208 | cfg.auth_options = INBOUND_AUTH; | ||
| 2209 | } | ||
| 2210 | |||
| 2211 | if( ppp_priv_area->pap == WANOPT_YES){ | ||
| 2212 | cfg.auth_options |=PAP_AUTH; | ||
| 2213 | printk(KERN_INFO "%s: Pap enabled\n", card->devname); | ||
| 2214 | } | ||
| 2215 | if( ppp_priv_area->chap == WANOPT_YES){ | ||
| 2216 | cfg.auth_options |= CHAP_AUTH; | ||
| 2217 | printk(KERN_INFO "%s: Chap enabled\n", card->devname); | ||
| 2218 | } | ||
| 2219 | |||
| 2220 | |||
| 2221 | if (ppp_priv_area->enable_IPX == WANOPT_YES){ | ||
| 2222 | printk(KERN_INFO "%s: Enabling IPX Protocol\n",card->devname); | ||
| 2223 | cfg.ipx_options = ENABLE_IPX | ROUTING_PROT_DEFAULT; | ||
| 2224 | }else{ | ||
| 2225 | cfg.ipx_options = DISABLE_IPX; | ||
| 2226 | } | ||
| 2227 | |||
| 2228 | switch (card->u.p.ip_mode) { | ||
| 2229 | |||
| 2230 | case WANOPT_PPP_STATIC: | ||
| 2231 | |||
| 2232 | printk(KERN_INFO "%s: PPP IP Mode: STATIC\n",card->devname); | ||
| 2233 | cfg.ip_options = L_AND_R_IP_NO_ASSIG | | ||
| 2234 | ENABLE_IP; | ||
| 2235 | cfg.ip_local = in_dev->ifa_list->ifa_local; | ||
| 2236 | cfg.ip_remote = in_dev->ifa_list->ifa_address; | ||
| 2237 | /* Debugging code used to check that IP addresses | ||
| 2238 | * obtained from the kernel are correct */ | ||
| 2239 | |||
| 2240 | NEX_PRINTK(KERN_INFO "Local %u.%u.%u.%u Remote %u.%u.%u.%u Name %s\n", | ||
| 2241 | NIPQUAD(ip_local),NIPQUAD(ip_remote), dev->name); | ||
| 2242 | break; | ||
| 2243 | |||
| 2244 | case WANOPT_PPP_HOST: | ||
| 2245 | |||
| 2246 | printk(KERN_INFO "%s: PPP IP Mode: HOST\n",card->devname); | ||
| 2247 | cfg.ip_options = L_IP_LOCAL_ASSIG | | ||
| 2248 | R_IP_LOCAL_ASSIG | | ||
| 2249 | ENABLE_IP; | ||
| 2250 | cfg.ip_local = in_dev->ifa_list->ifa_local; | ||
| 2251 | cfg.ip_remote = in_dev->ifa_list->ifa_address; | ||
| 2252 | /* Debugging code used to check that IP addresses | ||
| 2253 | * obtained from the kernel are correct */ | ||
| 2254 | NEX_PRINTK (KERN_INFO "Local %u.%u.%u.%u Remote %u.%u.%u.%u Name %s\n", | ||
| 2255 | NIPQUAD(ip_local),NIPQUAD(ip_remote), dev->name); | ||
| 2256 | |||
| 2257 | break; | ||
| 2258 | |||
| 2259 | case WANOPT_PPP_PEER: | ||
| 2260 | |||
| 2261 | printk(KERN_INFO "%s: PPP IP Mode: PEER\n",card->devname); | ||
| 2262 | cfg.ip_options = L_IP_REMOTE_ASSIG | | ||
| 2263 | R_IP_REMOTE_ASSIG | | ||
| 2264 | ENABLE_IP; | ||
| 2265 | cfg.ip_local = 0x00; | ||
| 2266 | cfg.ip_remote = 0x00; | ||
| 2267 | break; | ||
| 2268 | |||
| 2269 | default: | ||
| 2270 | printk(KERN_INFO "%s: ERROR: Unsupported PPP Mode Selected\n", | ||
| 2271 | card->devname); | ||
| 2272 | printk(KERN_INFO "%s: PPP IP Modes: STATIC, PEER or HOST\n", | ||
| 2273 | card->devname); | ||
| 2274 | return 1; | ||
| 2275 | } | ||
| 2276 | |||
| 2277 | return ppp_configure(card, &cfg); | ||
| 2278 | } | ||
| 2279 | |||
| 2280 | /*============================================================================ | ||
| 2281 | * Show disconnection cause. | ||
| 2282 | */ | ||
| 2283 | static void show_disc_cause(sdla_t *card, unsigned cause) | ||
| 2284 | { | ||
| 2285 | if (cause & 0x0802) | ||
| 2286 | |||
| 2287 | printk(KERN_INFO "%s: link terminated by peer\n", | ||
| 2288 | card->devname); | ||
| 2289 | |||
| 2290 | else if (cause & 0x0004) | ||
| 2291 | |||
| 2292 | printk(KERN_INFO "%s: link terminated by user\n", | ||
| 2293 | card->devname); | ||
| 2294 | |||
| 2295 | else if (cause & 0x0008) | ||
| 2296 | |||
| 2297 | printk(KERN_INFO "%s: authentication failed\n", card->devname); | ||
| 2298 | |||
| 2299 | else if (cause & 0x0010) | ||
| 2300 | |||
| 2301 | printk(KERN_INFO | ||
| 2302 | "%s: authentication protocol negotiation failed\n", | ||
| 2303 | card->devname); | ||
| 2304 | |||
| 2305 | else if (cause & 0x0020) | ||
| 2306 | |||
| 2307 | printk(KERN_INFO | ||
| 2308 | "%s: peer's request for authentication rejected\n", | ||
| 2309 | card->devname); | ||
| 2310 | |||
| 2311 | else if (cause & 0x0040) | ||
| 2312 | |||
| 2313 | printk(KERN_INFO "%s: MRU option rejected by peer\n", | ||
| 2314 | card->devname); | ||
| 2315 | |||
| 2316 | else if (cause & 0x0080) | ||
| 2317 | |||
| 2318 | printk(KERN_INFO "%s: peer's MRU was too small\n", | ||
| 2319 | card->devname); | ||
| 2320 | |||
| 2321 | else if (cause & 0x0100) | ||
| 2322 | |||
| 2323 | printk(KERN_INFO "%s: failed to negotiate peer's LCP options\n", | ||
| 2324 | card->devname); | ||
| 2325 | |||
| 2326 | else if (cause & 0x0200) | ||
| 2327 | |||
| 2328 | printk(KERN_INFO "%s: failed to negotiate peer's IPCP options\n" | ||
| 2329 | , card->devname); | ||
| 2330 | |||
| 2331 | else if (cause & 0x0400) | ||
| 2332 | |||
| 2333 | printk(KERN_INFO | ||
| 2334 | "%s: failed to negotiate peer's IPXCP options\n", | ||
| 2335 | card->devname); | ||
| 2336 | } | ||
| 2337 | |||
| 2338 | /*============================================================================= | ||
| 2339 | * Process UDP call of type PTPIPEAB. | ||
| 2340 | */ | ||
| 2341 | static void process_udp_mgmt_pkt(sdla_t *card, struct net_device *dev, | ||
| 2342 | ppp_private_area_t *ppp_priv_area ) | ||
| 2343 | { | ||
| 2344 | unsigned char buf2[5]; | ||
| 2345 | unsigned char *buf; | ||
| 2346 | unsigned int frames, len; | ||
| 2347 | struct sk_buff *new_skb; | ||
| 2348 | unsigned short data_length, buffer_length, real_len; | ||
| 2349 | unsigned long data_ptr; | ||
| 2350 | int udp_mgmt_req_valid = 1; | ||
| 2351 | ppp_mbox_t *mbox = card->mbox; | ||
| 2352 | struct timeval tv; | ||
| 2353 | int err; | ||
| 2354 | ppp_udp_pkt_t *ppp_udp_pkt = (ppp_udp_pkt_t*)&ppp_priv_area->udp_pkt_data; | ||
| 2355 | |||
| 2356 | memcpy(&buf2, &card->wandev.udp_port, 2 ); | ||
| 2357 | |||
| 2358 | |||
| 2359 | if(ppp_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { | ||
| 2360 | |||
| 2361 | switch(ppp_udp_pkt->cblock.command) { | ||
| 2362 | |||
| 2363 | case PPIPE_GET_IBA_DATA: | ||
| 2364 | case PPP_READ_CONFIG: | ||
| 2365 | case PPP_GET_CONNECTION_INFO: | ||
| 2366 | case PPIPE_ROUTER_UP_TIME: | ||
| 2367 | case PPP_READ_STATISTICS: | ||
| 2368 | case PPP_READ_ERROR_STATS: | ||
| 2369 | case PPP_READ_PACKET_STATS: | ||
| 2370 | case PPP_READ_LCP_STATS: | ||
| 2371 | case PPP_READ_IPCP_STATS: | ||
| 2372 | case PPP_READ_IPXCP_STATS: | ||
| 2373 | case PPP_READ_PAP_STATS: | ||
| 2374 | case PPP_READ_CHAP_STATS: | ||
| 2375 | case PPP_READ_CODE_VERSION: | ||
| 2376 | udp_mgmt_req_valid = 1; | ||
| 2377 | break; | ||
| 2378 | |||
| 2379 | default: | ||
| 2380 | udp_mgmt_req_valid = 0; | ||
| 2381 | break; | ||
| 2382 | } | ||
| 2383 | } | ||
| 2384 | |||
| 2385 | if(!udp_mgmt_req_valid) { | ||
| 2386 | |||
| 2387 | /* set length to 0 */ | ||
| 2388 | ppp_udp_pkt->cblock.length = 0x00; | ||
| 2389 | |||
| 2390 | /* set return code */ | ||
| 2391 | ppp_udp_pkt->cblock.result = 0xCD; | ||
| 2392 | ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_direction_err; | ||
| 2393 | |||
| 2394 | if (net_ratelimit()){ | ||
| 2395 | printk(KERN_INFO | ||
| 2396 | "%s: Warning, Illegal UDP command attempted from network: %x\n", | ||
| 2397 | card->devname,ppp_udp_pkt->cblock.command); | ||
| 2398 | } | ||
| 2399 | } else { | ||
| 2400 | /* Initialize the trace element */ | ||
| 2401 | trace_element_t trace_element; | ||
| 2402 | |||
| 2403 | switch (ppp_udp_pkt->cblock.command){ | ||
| 2404 | |||
| 2405 | /* PPIPE_ENABLE_TRACING */ | ||
| 2406 | case PPIPE_ENABLE_TRACING: | ||
| 2407 | if (!card->TracingEnabled) { | ||
| 2408 | |||
| 2409 | /* OPERATE_DATALINE_MONITOR */ | ||
| 2410 | mbox->cmd.command = PPP_DATALINE_MONITOR; | ||
| 2411 | mbox->cmd.length = 0x01; | ||
| 2412 | mbox->data[0] = ppp_udp_pkt->data[0]; | ||
| 2413 | err = sdla_exec(mbox) ? | ||
| 2414 | mbox->cmd.result : CMD_TIMEOUT; | ||
| 2415 | |||
| 2416 | if (err != CMD_OK) { | ||
| 2417 | |||
| 2418 | ppp_error(card, err, mbox); | ||
| 2419 | card->TracingEnabled = 0; | ||
| 2420 | |||
| 2421 | /* set the return code */ | ||
| 2422 | |||
| 2423 | ppp_udp_pkt->cblock.result = mbox->cmd.result; | ||
| 2424 | mbox->cmd.length = 0; | ||
| 2425 | break; | ||
| 2426 | } | ||
| 2427 | |||
| 2428 | sdla_peek(&card->hw, 0xC000, &buf2, 2); | ||
| 2429 | |||
| 2430 | ppp_priv_area->curr_trace_addr = 0; | ||
| 2431 | memcpy(&ppp_priv_area->curr_trace_addr, &buf2, 2); | ||
| 2432 | ppp_priv_area->start_trace_addr = | ||
| 2433 | ppp_priv_area->curr_trace_addr; | ||
| 2434 | ppp_priv_area->end_trace_addr = | ||
| 2435 | ppp_priv_area->start_trace_addr + END_OFFSET; | ||
| 2436 | |||
| 2437 | /* MAX_SEND_BUFFER_SIZE - 28 (IP header) | ||
| 2438 | - 32 (ppipemon CBLOCK) */ | ||
| 2439 | available_buffer_space = MAX_LGTH_UDP_MGNT_PKT - | ||
| 2440 | sizeof(ip_pkt_t)- | ||
| 2441 | sizeof(udp_pkt_t)- | ||
| 2442 | sizeof(wp_mgmt_t)- | ||
| 2443 | sizeof(cblock_t); | ||
| 2444 | } | ||
| 2445 | ppp_udp_pkt->cblock.result = 0; | ||
| 2446 | mbox->cmd.length = 0; | ||
| 2447 | card->TracingEnabled = 1; | ||
| 2448 | break; | ||
| 2449 | |||
| 2450 | /* PPIPE_DISABLE_TRACING */ | ||
| 2451 | case PPIPE_DISABLE_TRACING: | ||
| 2452 | |||
| 2453 | if(card->TracingEnabled) { | ||
| 2454 | |||
| 2455 | /* OPERATE_DATALINE_MONITOR */ | ||
| 2456 | mbox->cmd.command = 0x33; | ||
| 2457 | mbox->cmd.length = 1; | ||
| 2458 | mbox->data[0] = 0x00; | ||
| 2459 | err = sdla_exec(mbox) ? | ||
| 2460 | mbox->cmd.result : CMD_TIMEOUT; | ||
| 2461 | |||
| 2462 | } | ||
| 2463 | |||
| 2464 | /*set return code*/ | ||
| 2465 | ppp_udp_pkt->cblock.result = 0; | ||
| 2466 | mbox->cmd.length = 0; | ||
| 2467 | card->TracingEnabled = 0; | ||
| 2468 | break; | ||
| 2469 | |||
| 2470 | /* PPIPE_GET_TRACE_INFO */ | ||
| 2471 | case PPIPE_GET_TRACE_INFO: | ||
| 2472 | |||
| 2473 | if(!card->TracingEnabled) { | ||
| 2474 | /* set return code */ | ||
| 2475 | ppp_udp_pkt->cblock.result = 1; | ||
| 2476 | mbox->cmd.length = 0; | ||
| 2477 | } | ||
| 2478 | |||
| 2479 | buffer_length = 0; | ||
| 2480 | |||
| 2481 | /* frames < 62, where 62 is the number of trace | ||
| 2482 | information elements. There is in total 496 | ||
| 2483 | bytes of space and each trace information | ||
| 2484 | element is 8 bytes. | ||
| 2485 | */ | ||
| 2486 | for ( frames=0; frames<62; frames++) { | ||
| 2487 | |||
| 2488 | trace_pkt_t *trace_pkt = (trace_pkt_t *) | ||
| 2489 | &ppp_udp_pkt->data[buffer_length]; | ||
| 2490 | |||
| 2491 | /* Read the whole trace packet */ | ||
| 2492 | sdla_peek(&card->hw, ppp_priv_area->curr_trace_addr, | ||
| 2493 | &trace_element, sizeof(trace_element_t)); | ||
| 2494 | |||
| 2495 | /* no data on board so exit */ | ||
| 2496 | if( trace_element.opp_flag == 0x00 ) | ||
| 2497 | break; | ||
| 2498 | |||
| 2499 | data_ptr = trace_element.trace_data_ptr; | ||
| 2500 | |||
| 2501 | /* See if there is actual data on the trace buffer */ | ||
| 2502 | if (data_ptr){ | ||
| 2503 | data_length = trace_element.trace_length; | ||
| 2504 | }else{ | ||
| 2505 | data_length = 0; | ||
| 2506 | ppp_udp_pkt->data[0] |= 0x02; | ||
| 2507 | } | ||
| 2508 | |||
| 2509 | //FIXME: Do we need this check | ||
| 2510 | if ((available_buffer_space - buffer_length) | ||
| 2511 | < (sizeof(trace_element_t)+1)){ | ||
| 2512 | |||
| 2513 | /*indicate we have more frames | ||
| 2514 | * on board and exit | ||
| 2515 | */ | ||
| 2516 | ppp_udp_pkt->data[0] |= 0x02; | ||
| 2517 | break; | ||
| 2518 | } | ||
| 2519 | |||
| 2520 | trace_pkt->status = trace_element.trace_type; | ||
| 2521 | trace_pkt->time_stamp = trace_element.trace_time_stamp; | ||
| 2522 | trace_pkt->real_length = trace_element.trace_length; | ||
| 2523 | |||
| 2524 | real_len = trace_element.trace_length; | ||
| 2525 | |||
| 2526 | if(data_ptr == 0){ | ||
| 2527 | trace_pkt->data_avail = 0x00; | ||
| 2528 | }else{ | ||
| 2529 | /* we can take it next time */ | ||
| 2530 | if ((available_buffer_space - buffer_length)< | ||
| 2531 | (real_len + sizeof(trace_pkt_t))){ | ||
| 2532 | |||
| 2533 | ppp_udp_pkt->data[0] |= 0x02; | ||
| 2534 | break; | ||
| 2535 | } | ||
| 2536 | trace_pkt->data_avail = 0x01; | ||
| 2537 | |||
| 2538 | /* get the data */ | ||
| 2539 | sdla_peek(&card->hw, data_ptr, | ||
| 2540 | &trace_pkt->data, | ||
| 2541 | real_len); | ||
| 2542 | } | ||
| 2543 | /* zero the opp flag to | ||
| 2544 | show we got the frame */ | ||
| 2545 | buf2[0] = 0x00; | ||
| 2546 | sdla_poke(&card->hw, ppp_priv_area->curr_trace_addr, | ||
| 2547 | &buf2, 1); | ||
| 2548 | |||
| 2549 | /* now move onto the next | ||
| 2550 | frame */ | ||
| 2551 | ppp_priv_area->curr_trace_addr += 8; | ||
| 2552 | |||
| 2553 | /* check if we passed the last address */ | ||
| 2554 | if ( ppp_priv_area->curr_trace_addr >= | ||
| 2555 | ppp_priv_area->end_trace_addr){ | ||
| 2556 | |||
| 2557 | ppp_priv_area->curr_trace_addr = | ||
| 2558 | ppp_priv_area->start_trace_addr; | ||
| 2559 | } | ||
| 2560 | |||
| 2561 | /* update buffer length and make sure its even */ | ||
| 2562 | |||
| 2563 | if ( trace_pkt->data_avail == 0x01 ) { | ||
| 2564 | buffer_length += real_len - 1; | ||
| 2565 | } | ||
| 2566 | |||
| 2567 | /* for the header */ | ||
| 2568 | buffer_length += 8; | ||
| 2569 | |||
| 2570 | if( buffer_length & 0x0001 ) | ||
| 2571 | buffer_length += 1; | ||
| 2572 | } | ||
| 2573 | |||
| 2574 | /* ok now set the total number of frames passed | ||
| 2575 | in the high 5 bits */ | ||
| 2576 | ppp_udp_pkt->data[0] |= (frames << 2); | ||
| 2577 | |||
| 2578 | /* set the data length */ | ||
| 2579 | mbox->cmd.length = buffer_length; | ||
| 2580 | ppp_udp_pkt->cblock.length = buffer_length; | ||
| 2581 | |||
| 2582 | /* set return code */ | ||
| 2583 | ppp_udp_pkt->cblock.result = 0; | ||
| 2584 | break; | ||
| 2585 | |||
| 2586 | /* PPIPE_GET_IBA_DATA */ | ||
| 2587 | case PPIPE_GET_IBA_DATA: | ||
| 2588 | |||
| 2589 | mbox->cmd.length = 0x09; | ||
| 2590 | |||
| 2591 | sdla_peek(&card->hw, 0xF003, &ppp_udp_pkt->data, | ||
| 2592 | mbox->cmd.length); | ||
| 2593 | |||
| 2594 | /* set the length of the data */ | ||
| 2595 | ppp_udp_pkt->cblock.length = 0x09; | ||
| 2596 | |||
| 2597 | /* set return code */ | ||
| 2598 | ppp_udp_pkt->cblock.result = 0x00; | ||
| 2599 | ppp_udp_pkt->cblock.result = 0; | ||
| 2600 | break; | ||
| 2601 | |||
| 2602 | /* PPIPE_FT1_READ_STATUS */ | ||
| 2603 | case PPIPE_FT1_READ_STATUS: | ||
| 2604 | sdla_peek(&card->hw, 0xF020, &ppp_udp_pkt->data[0], 2); | ||
| 2605 | ppp_udp_pkt->cblock.length = mbox->cmd.length = 2; | ||
| 2606 | ppp_udp_pkt->cblock.result = 0; | ||
| 2607 | break; | ||
| 2608 | |||
| 2609 | case PPIPE_FLUSH_DRIVER_STATS: | ||
| 2610 | init_ppp_priv_struct( ppp_priv_area ); | ||
| 2611 | init_global_statistics( card ); | ||
| 2612 | mbox->cmd.length = 0; | ||
| 2613 | ppp_udp_pkt->cblock.result = 0; | ||
| 2614 | break; | ||
| 2615 | |||
| 2616 | |||
| 2617 | case PPIPE_ROUTER_UP_TIME: | ||
| 2618 | |||
| 2619 | do_gettimeofday( &tv ); | ||
| 2620 | ppp_priv_area->router_up_time = tv.tv_sec - | ||
| 2621 | ppp_priv_area->router_start_time; | ||
| 2622 | *(unsigned long *)&ppp_udp_pkt->data = ppp_priv_area->router_up_time; | ||
| 2623 | mbox->cmd.length = 4; | ||
| 2624 | ppp_udp_pkt->cblock.result = 0; | ||
| 2625 | break; | ||
| 2626 | |||
| 2627 | /* PPIPE_DRIVER_STATISTICS */ | ||
| 2628 | case PPIPE_DRIVER_STAT_IFSEND: | ||
| 2629 | memcpy(&ppp_udp_pkt->data, &ppp_priv_area->if_send_stat, | ||
| 2630 | sizeof(if_send_stat_t)); | ||
| 2631 | |||
| 2632 | |||
| 2633 | ppp_udp_pkt->cblock.result = 0; | ||
| 2634 | ppp_udp_pkt->cblock.length = sizeof(if_send_stat_t); | ||
| 2635 | mbox->cmd.length = sizeof(if_send_stat_t); | ||
| 2636 | break; | ||
| 2637 | |||
| 2638 | case PPIPE_DRIVER_STAT_INTR: | ||
| 2639 | memcpy(&ppp_udp_pkt->data, &card->statistics, | ||
| 2640 | sizeof(global_stats_t)); | ||
| 2641 | |||
| 2642 | memcpy(&ppp_udp_pkt->data+sizeof(global_stats_t), | ||
| 2643 | &ppp_priv_area->rx_intr_stat, | ||
| 2644 | sizeof(rx_intr_stat_t)); | ||
| 2645 | |||
| 2646 | ppp_udp_pkt->cblock.result = 0; | ||
| 2647 | ppp_udp_pkt->cblock.length = sizeof(global_stats_t)+ | ||
| 2648 | sizeof(rx_intr_stat_t); | ||
| 2649 | mbox->cmd.length = ppp_udp_pkt->cblock.length; | ||
| 2650 | break; | ||
| 2651 | |||
| 2652 | case PPIPE_DRIVER_STAT_GEN: | ||
| 2653 | memcpy( &ppp_udp_pkt->data, | ||
| 2654 | &ppp_priv_area->pipe_mgmt_stat, | ||
| 2655 | sizeof(pipe_mgmt_stat_t)); | ||
| 2656 | |||
| 2657 | memcpy(&ppp_udp_pkt->data+sizeof(pipe_mgmt_stat_t), | ||
| 2658 | &card->statistics, sizeof(global_stats_t)); | ||
| 2659 | |||
| 2660 | ppp_udp_pkt->cblock.result = 0; | ||
| 2661 | ppp_udp_pkt->cblock.length = sizeof(global_stats_t)+ | ||
| 2662 | sizeof(rx_intr_stat_t); | ||
| 2663 | mbox->cmd.length = ppp_udp_pkt->cblock.length; | ||
| 2664 | break; | ||
| 2665 | |||
| 2666 | |||
| 2667 | /* FT1 MONITOR STATUS */ | ||
| 2668 | case FT1_MONITOR_STATUS_CTRL: | ||
| 2669 | |||
| 2670 | /* Enable FT1 MONITOR STATUS */ | ||
| 2671 | if( ppp_udp_pkt->data[0] == 1) { | ||
| 2672 | |||
| 2673 | if( rCount++ != 0 ) { | ||
| 2674 | ppp_udp_pkt->cblock.result = 0; | ||
| 2675 | mbox->cmd.length = 1; | ||
| 2676 | break; | ||
| 2677 | } | ||
| 2678 | } | ||
| 2679 | |||
| 2680 | /* Disable FT1 MONITOR STATUS */ | ||
| 2681 | if( ppp_udp_pkt->data[0] == 0) { | ||
| 2682 | |||
| 2683 | if( --rCount != 0) { | ||
| 2684 | ppp_udp_pkt->cblock.result = 0; | ||
| 2685 | mbox->cmd.length = 1; | ||
| 2686 | break; | ||
| 2687 | } | ||
| 2688 | } | ||
| 2689 | goto udp_dflt_cmd; | ||
| 2690 | |||
| 2691 | /* WARNING: FIXME: This should be fixed. | ||
| 2692 | * The FT1 Status Ctrl doesn't have a break | ||
| 2693 | * statment. Thus, no code must be inserted | ||
| 2694 | * HERE: between default and above case statement */ | ||
| 2695 | |||
| 2696 | default: | ||
| 2697 | udp_dflt_cmd: | ||
| 2698 | |||
| 2699 | /* it's a board command */ | ||
| 2700 | mbox->cmd.command = ppp_udp_pkt->cblock.command; | ||
| 2701 | mbox->cmd.length = ppp_udp_pkt->cblock.length; | ||
| 2702 | |||
| 2703 | if(mbox->cmd.length) { | ||
| 2704 | memcpy(&mbox->data,(unsigned char *)ppp_udp_pkt->data, | ||
| 2705 | mbox->cmd.length); | ||
| 2706 | } | ||
| 2707 | |||
| 2708 | /* run the command on the board */ | ||
| 2709 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2710 | |||
| 2711 | if (err != CMD_OK) { | ||
| 2712 | |||
| 2713 | ppp_error(card, err, mbox); | ||
| 2714 | ++ppp_priv_area->pipe_mgmt_stat. | ||
| 2715 | UDP_PIPE_mgmt_adptr_cmnd_timeout; | ||
| 2716 | break; | ||
| 2717 | } | ||
| 2718 | |||
| 2719 | ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_OK; | ||
| 2720 | |||
| 2721 | /* copy the result back to our buffer */ | ||
| 2722 | memcpy(&ppp_udp_pkt->cblock,mbox, sizeof(cblock_t)); | ||
| 2723 | |||
| 2724 | if(mbox->cmd.length) { | ||
| 2725 | memcpy(&ppp_udp_pkt->data,&mbox->data,mbox->cmd.length); | ||
| 2726 | } | ||
| 2727 | |||
| 2728 | } /* end of switch */ | ||
| 2729 | } /* end of else */ | ||
| 2730 | |||
| 2731 | /* Fill UDP TTL */ | ||
| 2732 | ppp_udp_pkt->ip_pkt.ttl = card->wandev.ttl; | ||
| 2733 | len = reply_udp(ppp_priv_area->udp_pkt_data, mbox->cmd.length); | ||
| 2734 | |||
| 2735 | if (ppp_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { | ||
| 2736 | |||
| 2737 | /* Make sure we are not already sending */ | ||
| 2738 | if (!test_bit(SEND_CRIT,&card->wandev.critical)){ | ||
| 2739 | ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_adptr; | ||
| 2740 | ppp_send(card,ppp_priv_area->udp_pkt_data,len,ppp_priv_area->protocol); | ||
| 2741 | } | ||
| 2742 | |||
| 2743 | } else { | ||
| 2744 | |||
| 2745 | /* Pass it up the stack | ||
| 2746 | Allocate socket buffer */ | ||
| 2747 | if ((new_skb = dev_alloc_skb(len)) != NULL) { | ||
| 2748 | |||
| 2749 | /* copy data into new_skb */ | ||
| 2750 | |||
| 2751 | buf = skb_put(new_skb, len); | ||
| 2752 | memcpy(buf,ppp_priv_area->udp_pkt_data, len); | ||
| 2753 | |||
| 2754 | ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_stack; | ||
| 2755 | |||
| 2756 | /* Decapsulate packet and pass it up the protocol | ||
| 2757 | stack */ | ||
| 2758 | new_skb->protocol = htons(ETH_P_IP); | ||
| 2759 | new_skb->dev = dev; | ||
| 2760 | new_skb->mac.raw = new_skb->data; | ||
| 2761 | netif_rx(new_skb); | ||
| 2762 | dev->last_rx = jiffies; | ||
| 2763 | |||
| 2764 | } else { | ||
| 2765 | |||
| 2766 | ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_no_socket; | ||
| 2767 | printk(KERN_INFO "no socket buffers available!\n"); | ||
| 2768 | } | ||
| 2769 | } | ||
| 2770 | |||
| 2771 | ppp_priv_area->udp_pkt_lgth = 0; | ||
| 2772 | |||
| 2773 | return; | ||
| 2774 | } | ||
| 2775 | |||
| 2776 | /*============================================================================= | ||
| 2777 | * Initial the ppp_private_area structure. | ||
| 2778 | */ | ||
| 2779 | static void init_ppp_priv_struct( ppp_private_area_t *ppp_priv_area ) | ||
| 2780 | { | ||
| 2781 | |||
| 2782 | memset(&ppp_priv_area->if_send_stat, 0, sizeof(if_send_stat_t)); | ||
| 2783 | memset(&ppp_priv_area->rx_intr_stat, 0, sizeof(rx_intr_stat_t)); | ||
| 2784 | memset(&ppp_priv_area->pipe_mgmt_stat, 0, sizeof(pipe_mgmt_stat_t)); | ||
| 2785 | } | ||
| 2786 | |||
| 2787 | /*============================================================================ | ||
| 2788 | * Initialize Global Statistics | ||
| 2789 | */ | ||
| 2790 | static void init_global_statistics( sdla_t *card ) | ||
| 2791 | { | ||
| 2792 | memset(&card->statistics, 0, sizeof(global_stats_t)); | ||
| 2793 | } | ||
| 2794 | |||
| 2795 | /*============================================================================ | ||
| 2796 | * Initialize Receive and Transmit Buffers. | ||
| 2797 | */ | ||
| 2798 | static void init_ppp_tx_rx_buff( sdla_t *card ) | ||
| 2799 | { | ||
| 2800 | ppp508_buf_info_t* info; | ||
| 2801 | |||
| 2802 | if (card->hw.type == SDLA_S514) { | ||
| 2803 | |||
| 2804 | info = (void*)(card->hw.dpmbase + PPP514_BUF_OFFS); | ||
| 2805 | |||
| 2806 | card->u.p.txbuf_base = (void*)(card->hw.dpmbase + | ||
| 2807 | info->txb_ptr); | ||
| 2808 | |||
| 2809 | card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base + | ||
| 2810 | (info->txb_num - 1); | ||
| 2811 | |||
| 2812 | card->u.p.rxbuf_base = (void*)(card->hw.dpmbase + | ||
| 2813 | info->rxb_ptr); | ||
| 2814 | |||
| 2815 | card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base + | ||
| 2816 | (info->rxb_num - 1); | ||
| 2817 | |||
| 2818 | } else { | ||
| 2819 | |||
| 2820 | info = (void*)(card->hw.dpmbase + PPP508_BUF_OFFS); | ||
| 2821 | |||
| 2822 | card->u.p.txbuf_base = (void*)(card->hw.dpmbase + | ||
| 2823 | (info->txb_ptr - PPP508_MB_VECT)); | ||
| 2824 | |||
| 2825 | card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base + | ||
| 2826 | (info->txb_num - 1); | ||
| 2827 | |||
| 2828 | card->u.p.rxbuf_base = (void*)(card->hw.dpmbase + | ||
| 2829 | (info->rxb_ptr - PPP508_MB_VECT)); | ||
| 2830 | |||
| 2831 | card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base + | ||
| 2832 | (info->rxb_num - 1); | ||
| 2833 | } | ||
| 2834 | |||
| 2835 | card->u.p.txbuf_next = (unsigned long*)&info->txb_nxt; | ||
| 2836 | card->u.p.rxbuf_next = (unsigned long*)&info->rxb1_ptr; | ||
| 2837 | |||
| 2838 | card->u.p.rx_base = info->rxb_base; | ||
| 2839 | card->u.p.rx_top = info->rxb_end; | ||
| 2840 | |||
| 2841 | card->u.p.txbuf = card->u.p.txbuf_base; | ||
| 2842 | card->rxmb = card->u.p.rxbuf_base; | ||
| 2843 | |||
| 2844 | } | ||
| 2845 | |||
| 2846 | /*============================================================================= | ||
| 2847 | * Read Connection Information (ie for Remote IP address assginment). | ||
| 2848 | * Called when ppp interface connected. | ||
| 2849 | */ | ||
| 2850 | static int read_info( sdla_t *card ) | ||
| 2851 | { | ||
| 2852 | struct net_device *dev = card->wandev.dev; | ||
| 2853 | ppp_private_area_t *ppp_priv_area = dev->priv; | ||
| 2854 | int err; | ||
| 2855 | |||
| 2856 | struct ifreq if_info; | ||
| 2857 | struct sockaddr_in *if_data1, *if_data2; | ||
| 2858 | mm_segment_t fs; | ||
| 2859 | |||
| 2860 | /* Set Local and remote addresses */ | ||
| 2861 | memset(&if_info, 0, sizeof(if_info)); | ||
| 2862 | strcpy(if_info.ifr_name, dev->name); | ||
| 2863 | |||
| 2864 | |||
| 2865 | fs = get_fs(); | ||
| 2866 | set_fs(get_ds()); /* get user space block */ | ||
| 2867 | |||
| 2868 | /* Change the local and remote ip address of the interface. | ||
| 2869 | * This will also add in the destination route. | ||
| 2870 | */ | ||
| 2871 | if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; | ||
| 2872 | if_data1->sin_addr.s_addr = ppp_priv_area->ip_local; | ||
| 2873 | if_data1->sin_family = AF_INET; | ||
| 2874 | err = devinet_ioctl( SIOCSIFADDR, &if_info ); | ||
| 2875 | if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; | ||
| 2876 | if_data2->sin_addr.s_addr = ppp_priv_area->ip_remote; | ||
| 2877 | if_data2->sin_family = AF_INET; | ||
| 2878 | err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); | ||
| 2879 | |||
| 2880 | set_fs(fs); /* restore old block */ | ||
| 2881 | |||
| 2882 | if (err) { | ||
| 2883 | printk (KERN_INFO "%s: Adding of route failed: %i\n", | ||
| 2884 | card->devname,err); | ||
| 2885 | printk (KERN_INFO "%s: Local : %u.%u.%u.%u\n", | ||
| 2886 | card->devname,NIPQUAD(ppp_priv_area->ip_local)); | ||
| 2887 | printk (KERN_INFO "%s: Remote: %u.%u.%u.%u\n", | ||
| 2888 | card->devname,NIPQUAD(ppp_priv_area->ip_remote)); | ||
| 2889 | } | ||
| 2890 | return err; | ||
| 2891 | } | ||
| 2892 | |||
| 2893 | /*============================================================================= | ||
| 2894 | * Remove Dynamic Route. | ||
| 2895 | * Called when ppp interface disconnected. | ||
| 2896 | */ | ||
| 2897 | |||
| 2898 | static void remove_route( sdla_t *card ) | ||
| 2899 | { | ||
| 2900 | |||
| 2901 | struct net_device *dev = card->wandev.dev; | ||
| 2902 | long ip_addr; | ||
| 2903 | int err; | ||
| 2904 | |||
| 2905 | mm_segment_t fs; | ||
| 2906 | struct ifreq if_info; | ||
| 2907 | struct sockaddr_in *if_data1; | ||
| 2908 | struct in_device *in_dev = dev->ip_ptr; | ||
| 2909 | struct in_ifaddr *ifa = in_dev->ifa_list; | ||
| 2910 | |||
| 2911 | ip_addr = ifa->ifa_local; | ||
| 2912 | |||
| 2913 | /* Set Local and remote addresses */ | ||
| 2914 | memset(&if_info, 0, sizeof(if_info)); | ||
| 2915 | strcpy(if_info.ifr_name, dev->name); | ||
| 2916 | |||
| 2917 | fs = get_fs(); | ||
| 2918 | set_fs(get_ds()); /* get user space block */ | ||
| 2919 | |||
| 2920 | /* Change the local ip address of the interface to 0. | ||
| 2921 | * This will also delete the destination route. | ||
| 2922 | */ | ||
| 2923 | if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; | ||
| 2924 | if_data1->sin_addr.s_addr = 0; | ||
| 2925 | if_data1->sin_family = AF_INET; | ||
| 2926 | err = devinet_ioctl( SIOCSIFADDR, &if_info ); | ||
| 2927 | |||
| 2928 | set_fs(fs); /* restore old block */ | ||
| 2929 | |||
| 2930 | |||
| 2931 | if (err) { | ||
| 2932 | printk (KERN_INFO "%s: Deleting dynamic route failed %d!\n", | ||
| 2933 | card->devname, err); | ||
| 2934 | return; | ||
| 2935 | }else{ | ||
| 2936 | printk (KERN_INFO "%s: PPP Deleting dynamic route %u.%u.%u.%u successfuly\n", | ||
| 2937 | card->devname, NIPQUAD(ip_addr)); | ||
| 2938 | } | ||
| 2939 | return; | ||
| 2940 | } | ||
| 2941 | |||
| 2942 | /*============================================================================= | ||
| 2943 | * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR | ||
| 2944 | * _TEST_COUNTER times. | ||
| 2945 | */ | ||
| 2946 | static int intr_test( sdla_t *card ) | ||
| 2947 | { | ||
| 2948 | ppp_mbox_t *mb = card->mbox; | ||
| 2949 | int err,i; | ||
| 2950 | |||
| 2951 | err = ppp_set_intr_mode( card, 0x08 ); | ||
| 2952 | |||
| 2953 | if (err == CMD_OK) { | ||
| 2954 | |||
| 2955 | for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) { | ||
| 2956 | /* Run command READ_CODE_VERSION */ | ||
| 2957 | memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); | ||
| 2958 | mb->cmd.length = 0; | ||
| 2959 | mb->cmd.command = PPP_READ_CODE_VERSION; | ||
| 2960 | err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; | ||
| 2961 | if (err != CMD_OK) | ||
| 2962 | ppp_error(card, err, mb); | ||
| 2963 | } | ||
| 2964 | } | ||
| 2965 | else return err; | ||
| 2966 | |||
| 2967 | err = ppp_set_intr_mode( card, 0 ); | ||
| 2968 | if (err != CMD_OK) | ||
| 2969 | return err; | ||
| 2970 | |||
| 2971 | return 0; | ||
| 2972 | } | ||
| 2973 | |||
| 2974 | /*============================================================================== | ||
| 2975 | * Determine what type of UDP call it is. DRVSTATS or PTPIPEAB ? | ||
| 2976 | */ | ||
| 2977 | static int udp_pkt_type( struct sk_buff *skb, sdla_t *card ) | ||
| 2978 | { | ||
| 2979 | unsigned char *sendpacket; | ||
| 2980 | unsigned char buf2[5]; | ||
| 2981 | ppp_udp_pkt_t *ppp_udp_pkt = (ppp_udp_pkt_t *)skb->data; | ||
| 2982 | |||
| 2983 | sendpacket = skb->data; | ||
| 2984 | memcpy(&buf2, &card->wandev.udp_port, 2); | ||
| 2985 | |||
| 2986 | if( ppp_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45 && /* IP packet */ | ||
| 2987 | sendpacket[9] == 0x11 && /* UDP packet */ | ||
| 2988 | sendpacket[22] == buf2[1] && /* UDP Port */ | ||
| 2989 | sendpacket[23] == buf2[0] && | ||
| 2990 | sendpacket[36] == 0x01 ) { | ||
| 2991 | |||
| 2992 | if ( sendpacket[28] == 0x50 && /* PTPIPEAB: Signature */ | ||
| 2993 | sendpacket[29] == 0x54 && | ||
| 2994 | sendpacket[30] == 0x50 && | ||
| 2995 | sendpacket[31] == 0x49 && | ||
| 2996 | sendpacket[32] == 0x50 && | ||
| 2997 | sendpacket[33] == 0x45 && | ||
| 2998 | sendpacket[34] == 0x41 && | ||
| 2999 | sendpacket[35] == 0x42 ){ | ||
| 3000 | |||
| 3001 | return UDP_PTPIPE_TYPE; | ||
| 3002 | |||
| 3003 | } else if(sendpacket[28] == 0x44 && /* DRVSTATS: Signature */ | ||
| 3004 | sendpacket[29] == 0x52 && | ||
| 3005 | sendpacket[30] == 0x56 && | ||
| 3006 | sendpacket[31] == 0x53 && | ||
| 3007 | sendpacket[32] == 0x54 && | ||
| 3008 | sendpacket[33] == 0x41 && | ||
| 3009 | sendpacket[34] == 0x54 && | ||
| 3010 | sendpacket[35] == 0x53 ){ | ||
| 3011 | |||
| 3012 | return UDP_DRVSTATS_TYPE; | ||
| 3013 | |||
| 3014 | } else | ||
| 3015 | return UDP_INVALID_TYPE; | ||
| 3016 | |||
| 3017 | } else | ||
| 3018 | return UDP_INVALID_TYPE; | ||
| 3019 | |||
| 3020 | } | ||
| 3021 | |||
| 3022 | /*============================================================================ | ||
| 3023 | * Check to see if the packet to be transmitted contains a broadcast or | ||
| 3024 | * multicast source IP address. | ||
| 3025 | */ | ||
| 3026 | |||
| 3027 | static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, | ||
| 3028 | struct sk_buff *skb) | ||
| 3029 | { | ||
| 3030 | u32 src_ip_addr; | ||
| 3031 | u32 broadcast_ip_addr = 0; | ||
| 3032 | struct in_device *in_dev; | ||
| 3033 | |||
| 3034 | /* read the IP source address from the outgoing packet */ | ||
| 3035 | src_ip_addr = *(u32 *)(skb->data + 12); | ||
| 3036 | |||
| 3037 | /* read the IP broadcast address for the device */ | ||
| 3038 | in_dev = dev->ip_ptr; | ||
| 3039 | if(in_dev != NULL) { | ||
| 3040 | struct in_ifaddr *ifa= in_dev->ifa_list; | ||
| 3041 | if(ifa != NULL) | ||
| 3042 | broadcast_ip_addr = ifa->ifa_broadcast; | ||
| 3043 | else | ||
| 3044 | return 0; | ||
| 3045 | } | ||
| 3046 | |||
| 3047 | /* check if the IP Source Address is a Broadcast address */ | ||
| 3048 | if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { | ||
| 3049 | printk(KERN_INFO "%s: Broadcast Source Address silently discarded\n", | ||
| 3050 | card->devname); | ||
| 3051 | return 1; | ||
| 3052 | } | ||
| 3053 | |||
| 3054 | /* check if the IP Source Address is a Multicast address */ | ||
| 3055 | if((ntohl(src_ip_addr) >= 0xE0000001) && | ||
| 3056 | (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { | ||
| 3057 | printk(KERN_INFO "%s: Multicast Source Address silently discarded\n", | ||
| 3058 | card->devname); | ||
| 3059 | return 1; | ||
| 3060 | } | ||
| 3061 | |||
| 3062 | return 0; | ||
| 3063 | } | ||
| 3064 | |||
| 3065 | void s508_lock (sdla_t *card, unsigned long *smp_flags) | ||
| 3066 | { | ||
| 3067 | spin_lock_irqsave(&card->wandev.lock, *smp_flags); | ||
| 3068 | } | ||
| 3069 | |||
| 3070 | void s508_unlock (sdla_t *card, unsigned long *smp_flags) | ||
| 3071 | { | ||
| 3072 | spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); | ||
| 3073 | } | ||
| 3074 | |||
| 3075 | static int read_connection_info (sdla_t *card) | ||
| 3076 | { | ||
| 3077 | ppp_mbox_t *mb = card->mbox; | ||
| 3078 | struct net_device *dev = card->wandev.dev; | ||
| 3079 | ppp_private_area_t *ppp_priv_area = dev->priv; | ||
| 3080 | ppp508_connect_info_t *ppp508_connect_info; | ||
| 3081 | int err; | ||
| 3082 | |||
| 3083 | memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); | ||
| 3084 | mb->cmd.length = 0; | ||
| 3085 | mb->cmd.command = PPP_GET_CONNECTION_INFO; | ||
| 3086 | err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; | ||
| 3087 | |||
| 3088 | if (err != CMD_OK) { | ||
| 3089 | ppp_error(card, err, mb); | ||
| 3090 | ppp_priv_area->ip_remote = 0; | ||
| 3091 | ppp_priv_area->ip_local = 0; | ||
| 3092 | } | ||
| 3093 | else { | ||
| 3094 | ppp508_connect_info = (ppp508_connect_info_t *)mb->data; | ||
| 3095 | ppp_priv_area->ip_remote = ppp508_connect_info->ip_remote; | ||
| 3096 | ppp_priv_area->ip_local = ppp508_connect_info->ip_local; | ||
| 3097 | |||
| 3098 | NEX_PRINTK(KERN_INFO "READ CONNECTION GOT IP ADDRESS %x, %x\n", | ||
| 3099 | ppp_priv_area->ip_remote, | ||
| 3100 | ppp_priv_area->ip_local); | ||
| 3101 | } | ||
| 3102 | |||
| 3103 | return err; | ||
| 3104 | } | ||
| 3105 | |||
| 3106 | /*=============================================================================== | ||
| 3107 | * config_ppp | ||
| 3108 | * | ||
| 3109 | * Configure the ppp protocol and enable communications. | ||
| 3110 | * | ||
| 3111 | * The if_open function binds this function to the poll routine. | ||
| 3112 | * Therefore, this function will run every time the ppp interface | ||
| 3113 | * is brought up. | ||
| 3114 | * | ||
| 3115 | * If the communications are not enabled, proceed to configure | ||
| 3116 | * the card and enable communications. | ||
| 3117 | * | ||
| 3118 | * If the communications are enabled, it means that the interface | ||
| 3119 | * was shutdown by ether the user or driver. In this case, we | ||
| 3120 | * have to check that the IP addresses have not changed. If | ||
| 3121 | * the IP addresses changed, we have to reconfigure the firmware | ||
| 3122 | * and update the changed IP addresses. Otherwise, just exit. | ||
| 3123 | */ | ||
| 3124 | static int config_ppp (sdla_t *card) | ||
| 3125 | { | ||
| 3126 | |||
| 3127 | struct net_device *dev = card->wandev.dev; | ||
| 3128 | ppp_flags_t *flags = card->flags; | ||
| 3129 | ppp_private_area_t *ppp_priv_area = dev->priv; | ||
| 3130 | |||
| 3131 | if (card->u.p.comm_enabled){ | ||
| 3132 | |||
| 3133 | if (ppp_priv_area->ip_local_tmp != ppp_priv_area->ip_local || | ||
| 3134 | ppp_priv_area->ip_remote_tmp != ppp_priv_area->ip_remote){ | ||
| 3135 | |||
| 3136 | /* The IP addersses have changed, we must | ||
| 3137 | * stop the communications and reconfigure | ||
| 3138 | * the card. Reason: the firmware must know | ||
| 3139 | * the local and remote IP addresses. */ | ||
| 3140 | disable_comm(card); | ||
| 3141 | wanpipe_set_state(card, WAN_DISCONNECTED); | ||
| 3142 | printk(KERN_INFO | ||
| 3143 | "%s: IP addresses changed!\n", | ||
| 3144 | card->devname); | ||
| 3145 | printk(KERN_INFO "%s: Restarting communications ...\n", | ||
| 3146 | card->devname); | ||
| 3147 | }else{ | ||
| 3148 | /* IP addresses are the same and the link is up, | ||
| 3149 | * we don't have to do anything here. Therefore, exit */ | ||
| 3150 | return 0; | ||
| 3151 | } | ||
| 3152 | } | ||
| 3153 | |||
| 3154 | /* Record the new IP addreses */ | ||
| 3155 | ppp_priv_area->ip_local = ppp_priv_area->ip_local_tmp; | ||
| 3156 | ppp_priv_area->ip_remote = ppp_priv_area->ip_remote_tmp; | ||
| 3157 | |||
| 3158 | if (config508(dev, card)){ | ||
| 3159 | printk(KERN_INFO "%s: Failed to configure PPP device\n", | ||
| 3160 | card->devname); | ||
| 3161 | return 0; | ||
| 3162 | } | ||
| 3163 | |||
| 3164 | if (ppp_set_intr_mode(card, PPP_INTR_RXRDY| | ||
| 3165 | PPP_INTR_TXRDY| | ||
| 3166 | PPP_INTR_MODEM| | ||
| 3167 | PPP_INTR_DISC | | ||
| 3168 | PPP_INTR_OPEN | | ||
| 3169 | PPP_INTR_DROP_DTR | | ||
| 3170 | PPP_INTR_TIMER)) { | ||
| 3171 | |||
| 3172 | printk(KERN_INFO "%s: Failed to configure board interrupts !\n", | ||
| 3173 | card->devname); | ||
| 3174 | return 0; | ||
| 3175 | } | ||
| 3176 | |||
| 3177 | /* Turn off the transmit and timer interrupt */ | ||
| 3178 | flags->imask &= ~(PPP_INTR_TXRDY | PPP_INTR_TIMER) ; | ||
| 3179 | |||
| 3180 | |||
| 3181 | /* If you are not the authenticator and any one of the protocol is | ||
| 3182 | * enabled then we call the set_out_bound_authentication. | ||
| 3183 | */ | ||
| 3184 | if ( !card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)) { | ||
| 3185 | if ( ppp_set_outbnd_auth(card, ppp_priv_area) ){ | ||
| 3186 | printk(KERN_INFO "%s: Outbound authentication failed !\n", | ||
| 3187 | card->devname); | ||
| 3188 | return 0; | ||
| 3189 | } | ||
| 3190 | } | ||
| 3191 | |||
| 3192 | /* If you are the authenticator and any one of the protocol is enabled | ||
| 3193 | * then we call the set_in_bound_authentication. | ||
| 3194 | */ | ||
| 3195 | if (card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)){ | ||
| 3196 | if (ppp_set_inbnd_auth(card, ppp_priv_area)){ | ||
| 3197 | printk(KERN_INFO "%s: Inbound authentication failed !\n", | ||
| 3198 | card->devname); | ||
| 3199 | return 0; | ||
| 3200 | } | ||
| 3201 | } | ||
| 3202 | |||
| 3203 | /* If we fail to enable communications here it's OK, | ||
| 3204 | * since the DTR timer will cause a disconnected, which | ||
| 3205 | * will retrigger communication in timer_intr() */ | ||
| 3206 | if (ppp_comm_enable(card) == CMD_OK) { | ||
| 3207 | wanpipe_set_state(card, WAN_CONNECTING); | ||
| 3208 | init_ppp_tx_rx_buff(card); | ||
| 3209 | } | ||
| 3210 | |||
| 3211 | return 0; | ||
| 3212 | } | ||
| 3213 | |||
| 3214 | /*============================================================ | ||
| 3215 | * ppp_poll | ||
| 3216 | * | ||
| 3217 | * Rationale: | ||
| 3218 | * We cannot manipulate the routing tables, or | ||
| 3219 | * ip addresses withing the interrupt. Therefore | ||
| 3220 | * we must perform such actons outside an interrupt | ||
| 3221 | * at a later time. | ||
| 3222 | * | ||
| 3223 | * Description: | ||
| 3224 | * PPP polling routine, responsible for | ||
| 3225 | * shutting down interfaces upon disconnect | ||
| 3226 | * and adding/removing routes. | ||
| 3227 | * | ||
| 3228 | * Usage: | ||
| 3229 | * This function is executed for each ppp | ||
| 3230 | * interface through a tq_schedule bottom half. | ||
| 3231 | * | ||
| 3232 | * trigger_ppp_poll() function is used to kick | ||
| 3233 | * the ppp_poll routine. | ||
| 3234 | */ | ||
| 3235 | static void ppp_poll(struct net_device *dev) | ||
| 3236 | { | ||
| 3237 | ppp_private_area_t *ppp_priv_area; | ||
| 3238 | sdla_t *card; | ||
| 3239 | u8 check_gateway=0; | ||
| 3240 | ppp_flags_t *flags; | ||
| 3241 | |||
| 3242 | if (!dev || (ppp_priv_area = dev->priv) == NULL) | ||
| 3243 | return; | ||
| 3244 | |||
| 3245 | card = ppp_priv_area->card; | ||
| 3246 | flags = card->flags; | ||
| 3247 | |||
| 3248 | /* Shutdown is in progress, stop what you are | ||
| 3249 | * doing and get out */ | ||
| 3250 | if (test_bit(PERI_CRIT,&card->wandev.critical)){ | ||
| 3251 | clear_bit(POLL_CRIT,&card->wandev.critical); | ||
| 3252 | return; | ||
| 3253 | } | ||
| 3254 | |||
| 3255 | /* if_open() function has triggered the polling routine | ||
| 3256 | * to determine the configured IP addresses. Once the | ||
| 3257 | * addresses are found, trigger the chdlc configuration */ | ||
| 3258 | if (test_bit(0,&ppp_priv_area->config_ppp)){ | ||
| 3259 | |||
| 3260 | ppp_priv_area->ip_local_tmp = get_ip_address(dev,WAN_LOCAL_IP); | ||
| 3261 | ppp_priv_area->ip_remote_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP); | ||
| 3262 | |||
| 3263 | if (ppp_priv_area->ip_local_tmp == ppp_priv_area->ip_remote_tmp && | ||
| 3264 | card->u.p.ip_mode == WANOPT_PPP_HOST){ | ||
| 3265 | |||
| 3266 | if (++ppp_priv_area->ip_error > MAX_IP_ERRORS){ | ||
| 3267 | printk(KERN_INFO "\n%s: --- WARNING ---\n", | ||
| 3268 | card->devname); | ||
| 3269 | printk(KERN_INFO "%s: The local IP address is the same as the\n", | ||
| 3270 | card->devname); | ||
| 3271 | printk(KERN_INFO "%s: Point-to-Point IP address.\n", | ||
| 3272 | card->devname); | ||
| 3273 | printk(KERN_INFO "%s: --- WARNING ---\n\n", | ||
| 3274 | card->devname); | ||
| 3275 | }else{ | ||
| 3276 | clear_bit(POLL_CRIT,&card->wandev.critical); | ||
| 3277 | ppp_priv_area->poll_delay_timer.expires = jiffies+HZ; | ||
| 3278 | add_timer(&ppp_priv_area->poll_delay_timer); | ||
| 3279 | return; | ||
| 3280 | } | ||
| 3281 | } | ||
| 3282 | |||
| 3283 | ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG; | ||
| 3284 | flags->imask |= PPP_INTR_TIMER; | ||
| 3285 | ppp_priv_area->ip_error=0; | ||
| 3286 | |||
| 3287 | clear_bit(0,&ppp_priv_area->config_ppp); | ||
| 3288 | clear_bit(POLL_CRIT,&card->wandev.critical); | ||
| 3289 | return; | ||
| 3290 | } | ||
| 3291 | |||
| 3292 | /* Dynamic interface implementation, as well as dynamic | ||
| 3293 | * routing. */ | ||
| 3294 | |||
| 3295 | switch (card->wandev.state) { | ||
| 3296 | |||
| 3297 | case WAN_DISCONNECTED: | ||
| 3298 | |||
| 3299 | /* If the dynamic interface configuration is on, and interface | ||
| 3300 | * is up, then bring down the netowrk interface */ | ||
| 3301 | |||
| 3302 | if (test_bit(DYN_OPT_ON,&ppp_priv_area->interface_down) && | ||
| 3303 | !test_bit(DEV_DOWN,&ppp_priv_area->interface_down) && | ||
| 3304 | card->wandev.dev->flags & IFF_UP){ | ||
| 3305 | |||
| 3306 | printk(KERN_INFO "%s: Interface %s down.\n", | ||
| 3307 | card->devname,card->wandev.dev->name); | ||
| 3308 | change_dev_flags(card->wandev.dev, | ||
| 3309 | (card->wandev.dev->flags&~IFF_UP)); | ||
| 3310 | set_bit(DEV_DOWN,&ppp_priv_area->interface_down); | ||
| 3311 | }else{ | ||
| 3312 | /* We need to check if the local IP address is | ||
| 3313 | * zero. If it is, we shouldn't try to remove it. | ||
| 3314 | * For some reason the kernel crashes badly if | ||
| 3315 | * we try to remove the route twice */ | ||
| 3316 | |||
| 3317 | if (card->wandev.dev->flags & IFF_UP && | ||
| 3318 | get_ip_address(card->wandev.dev,WAN_LOCAL_IP) && | ||
| 3319 | card->u.p.ip_mode == WANOPT_PPP_PEER){ | ||
| 3320 | |||
| 3321 | remove_route(card); | ||
| 3322 | } | ||
| 3323 | } | ||
| 3324 | break; | ||
| 3325 | |||
| 3326 | case WAN_CONNECTED: | ||
| 3327 | |||
| 3328 | /* In SMP machine this code can execute before the interface | ||
| 3329 | * comes up. In this case, we must make sure that we do not | ||
| 3330 | * try to bring up the interface before dev_open() is finished */ | ||
| 3331 | |||
| 3332 | |||
| 3333 | /* DEV_DOWN will be set only when we bring down the interface | ||
| 3334 | * for the very first time. This way we know that it was us | ||
| 3335 | * that brought the interface down */ | ||
| 3336 | |||
| 3337 | if (test_bit(DYN_OPT_ON,&ppp_priv_area->interface_down) && | ||
| 3338 | test_bit(DEV_DOWN, &ppp_priv_area->interface_down) && | ||
| 3339 | !(card->wandev.dev->flags & IFF_UP)){ | ||
| 3340 | |||
| 3341 | printk(KERN_INFO "%s: Interface %s up.\n", | ||
| 3342 | card->devname,card->wandev.dev->name); | ||
| 3343 | |||
| 3344 | change_dev_flags(card->wandev.dev,(card->wandev.dev->flags|IFF_UP)); | ||
| 3345 | clear_bit(DEV_DOWN,&ppp_priv_area->interface_down); | ||
| 3346 | check_gateway=1; | ||
| 3347 | } | ||
| 3348 | |||
| 3349 | if ((card->u.p.ip_mode == WANOPT_PPP_PEER) && | ||
| 3350 | test_bit(1,&Read_connection_info)) { | ||
| 3351 | |||
| 3352 | process_route(card); | ||
| 3353 | clear_bit(1,&Read_connection_info); | ||
| 3354 | check_gateway=1; | ||
| 3355 | } | ||
| 3356 | |||
| 3357 | if (ppp_priv_area->gateway && check_gateway) | ||
| 3358 | add_gateway(card,dev); | ||
| 3359 | |||
| 3360 | break; | ||
| 3361 | } | ||
| 3362 | clear_bit(POLL_CRIT,&card->wandev.critical); | ||
| 3363 | return; | ||
| 3364 | } | ||
| 3365 | |||
| 3366 | /*============================================================ | ||
| 3367 | * trigger_ppp_poll | ||
| 3368 | * | ||
| 3369 | * Description: | ||
| 3370 | * Add a ppp_poll() task into a tq_scheduler bh handler | ||
| 3371 | * for a specific interface. This will kick | ||
| 3372 | * the ppp_poll() routine at a later time. | ||
| 3373 | * | ||
| 3374 | * Usage: | ||
| 3375 | * Interrupts use this to defer a taks to | ||
| 3376 | * a polling routine. | ||
| 3377 | * | ||
| 3378 | */ | ||
| 3379 | |||
| 3380 | static void trigger_ppp_poll(struct net_device *dev) | ||
| 3381 | { | ||
| 3382 | ppp_private_area_t *ppp_priv_area; | ||
| 3383 | if ((ppp_priv_area=dev->priv) != NULL){ | ||
| 3384 | |||
| 3385 | sdla_t *card = ppp_priv_area->card; | ||
| 3386 | |||
| 3387 | if (test_bit(PERI_CRIT,&card->wandev.critical)){ | ||
| 3388 | return; | ||
| 3389 | } | ||
| 3390 | |||
| 3391 | if (test_and_set_bit(POLL_CRIT,&card->wandev.critical)){ | ||
| 3392 | return; | ||
| 3393 | } | ||
| 3394 | |||
| 3395 | schedule_work(&ppp_priv_area->poll_work); | ||
| 3396 | } | ||
| 3397 | return; | ||
| 3398 | } | ||
| 3399 | |||
| 3400 | static void ppp_poll_delay (unsigned long dev_ptr) | ||
| 3401 | { | ||
| 3402 | struct net_device *dev = (struct net_device *)dev_ptr; | ||
| 3403 | trigger_ppp_poll(dev); | ||
| 3404 | } | ||
| 3405 | |||
| 3406 | /*============================================================ | ||
| 3407 | * detect_and_fix_tx_bug | ||
| 3408 | * | ||
| 3409 | * Description: | ||
| 3410 | * On connect, if the board tx buffer ptr is not the same | ||
| 3411 | * as the driver tx buffer ptr, we found a firmware bug. | ||
| 3412 | * Report the bug to the above layer. To fix the | ||
| 3413 | * error restart communications again. | ||
| 3414 | * | ||
| 3415 | * Usage: | ||
| 3416 | * | ||
| 3417 | */ | ||
| 3418 | |||
| 3419 | static int detect_and_fix_tx_bug (sdla_t *card) | ||
| 3420 | { | ||
| 3421 | if (((unsigned long)card->u.p.txbuf_base&0xFFF) != ((*card->u.p.txbuf_next)&0xFFF)){ | ||
| 3422 | NEX_PRINTK(KERN_INFO "Major Error, Fix the bug\n"); | ||
| 3423 | return 1; | ||
| 3424 | } | ||
| 3425 | return 0; | ||
| 3426 | } | ||
| 3427 | |||
| 3428 | MODULE_LICENSE("GPL"); | ||
| 3429 | |||
| 3430 | /****** End *****************************************************************/ | ||
diff --git a/drivers/net/wan/sdla_x25.c b/drivers/net/wan/sdla_x25.c deleted file mode 100644 index 63f846d6f3a6..000000000000 --- a/drivers/net/wan/sdla_x25.c +++ /dev/null | |||
| @@ -1,5497 +0,0 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * sdla_x25.c WANPIPE(tm) Multiprotocol WAN Link Driver. X.25 module. | ||
| 3 | * | ||
| 4 | * Author: Nenad Corbic <ncorbic@sangoma.com> | ||
| 5 | * | ||
| 6 | * Copyright: (c) 1995-2001 Sangoma Technologies Inc. | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or | ||
| 9 | * modify it under the terms of the GNU General Public License | ||
| 10 | * as published by the Free Software Foundation; either version | ||
| 11 | * 2 of the License, or (at your option) any later version. | ||
| 12 | * ============================================================================ | ||
| 13 | * Apr 03, 2001 Nenad Corbic o Fixed the rx_skb=NULL bug in x25 in rx_intr(). | ||
| 14 | * Dec 26, 2000 Nenad Corbic o Added a new polling routine, that uses | ||
| 15 | * a kernel timer (more efficient). | ||
| 16 | * Dec 25, 2000 Nenad Corbic o Updated for 2.4.X kernel | ||
| 17 | * Jul 26, 2000 Nenad Corbic o Increased the local packet buffering | ||
| 18 | * for API to 4096+header_size. | ||
| 19 | * Jul 17, 2000 Nenad Corbic o Fixed the x25 startup bug. Enable | ||
| 20 | * communications only after all interfaces | ||
| 21 | * come up. HIGH SVC/PVC is used to calculate | ||
| 22 | * the number of channels. | ||
| 23 | * Enable protocol only after all interfaces | ||
| 24 | * are enabled. | ||
| 25 | * Jul 10, 2000 Nenad Corbic o Fixed the M_BIT bug. | ||
| 26 | * Apr 25, 2000 Nenad Corbic o Pass Modem messages to the API. | ||
| 27 | * Disable idle timeout in X25 API. | ||
| 28 | * Apr 14, 2000 Nenad Corbic o Fixed: Large LCN number support. | ||
| 29 | * Maximum LCN number is 4095. | ||
| 30 | * Maximum number of X25 channels is 255. | ||
| 31 | * Apr 06, 2000 Nenad Corbic o Added SMP Support. | ||
| 32 | * Mar 29, 2000 Nenad Corbic o Added support for S514 PCI Card | ||
| 33 | * Mar 23, 2000 Nenad Corbic o Improved task queue, BH handling. | ||
| 34 | * Mar 14, 2000 Nenad Corbic o Updated Protocol Violation handling | ||
| 35 | * routines. Bug Fix. | ||
| 36 | * Mar 10, 2000 Nenad Corbic o Bug Fix: corrupted mbox recovery. | ||
| 37 | * Mar 09, 2000 Nenad Corbic o Fixed the auto HDLC bug. | ||
| 38 | * Mar 08, 2000 Nenad Corbic o Fixed LAPB HDLC startup problems. | ||
| 39 | * Application must bring the link up | ||
| 40 | * before tx/rx, and bring the | ||
| 41 | * link down on close(). | ||
| 42 | * Mar 06, 2000 Nenad Corbic o Added an option for logging call setup | ||
| 43 | * information. | ||
| 44 | * Feb 29, 2000 Nenad Corbic o Added support for LAPB HDLC API | ||
| 45 | * Feb 25, 2000 Nenad Corbic o Fixed the modem failure handling. | ||
| 46 | * No Modem OOB message will be passed | ||
| 47 | * to the user. | ||
| 48 | * Feb 21, 2000 Nenad Corbic o Added Xpipemon Debug Support | ||
| 49 | * Dec 30, 1999 Nenad Corbic o Socket based X25API | ||
| 50 | * Sep 17, 1998 Jaspreet Singh o Updates for 2.2.X kernel | ||
| 51 | * Mar 15, 1998 Alan Cox o 2.1.x porting | ||
| 52 | * Dec 19, 1997 Jaspreet Singh o Added multi-channel IPX support | ||
| 53 | * Nov 27, 1997 Jaspreet Singh o Added protection against enabling of irqs | ||
| 54 | * when they are disabled. | ||
| 55 | * Nov 17, 1997 Farhan Thawar o Added IPX support | ||
| 56 | * o Changed if_send() to now buffer packets when | ||
| 57 | * the board is busy | ||
| 58 | * o Removed queueing of packets via the polling | ||
| 59 | * routing | ||
| 60 | * o Changed if_send() critical flags to properly | ||
| 61 | * handle race conditions | ||
| 62 | * Nov 06, 1997 Farhan Thawar o Added support for SVC timeouts | ||
| 63 | * o Changed PVC encapsulation to ETH_P_IP | ||
| 64 | * Jul 21, 1997 Jaspreet Singh o Fixed freeing up of buffers using kfree() | ||
| 65 | * when packets are received. | ||
| 66 | * Mar 11, 1997 Farhan Thawar Version 3.1.1 | ||
| 67 | * o added support for V35 | ||
| 68 | * o changed if_send() to return 0 if | ||
| 69 | * wandev.critical() is true | ||
| 70 | * o free socket buffer in if_send() if | ||
| 71 | * returning 0 | ||
| 72 | * o added support for single '@' address to | ||
| 73 | * accept all incoming calls | ||
| 74 | * o fixed bug in set_chan_state() to disconnect | ||
| 75 | * Jan 15, 1997 Gene Kozin Version 3.1.0 | ||
| 76 | * o implemented exec() entry point | ||
| 77 | * Jan 07, 1997 Gene Kozin Initial version. | ||
| 78 | *****************************************************************************/ | ||
| 79 | |||
| 80 | /*====================================================== | ||
| 81 | * Includes | ||
| 82 | *=====================================================*/ | ||
| 83 | |||
| 84 | #include <linux/module.h> | ||
| 85 | #include <linux/kernel.h> /* printk(), and other useful stuff */ | ||
| 86 | #include <linux/stddef.h> /* offsetof(), etc. */ | ||
| 87 | #include <linux/errno.h> /* return codes */ | ||
| 88 | #include <linux/string.h> /* inline memset(), etc. */ | ||
| 89 | #include <linux/ctype.h> | ||
| 90 | #include <linux/slab.h> /* kmalloc(), kfree() */ | ||
| 91 | #include <linux/wanrouter.h> /* WAN router definitions */ | ||
| 92 | #include <linux/wanpipe.h> /* WANPIPE common user API definitions */ | ||
| 93 | #include <linux/workqueue.h> | ||
| 94 | #include <linux/jiffies.h> /* time_after() macro */ | ||
| 95 | #include <asm/byteorder.h> /* htons(), etc. */ | ||
| 96 | #include <asm/atomic.h> | ||
| 97 | #include <linux/delay.h> /* Experimental delay */ | ||
| 98 | |||
| 99 | #include <asm/uaccess.h> | ||
| 100 | |||
| 101 | #include <linux/if.h> | ||
| 102 | #include <linux/if_arp.h> | ||
| 103 | #include <linux/sdla_x25.h> /* X.25 firmware API definitions */ | ||
| 104 | #include <linux/if_wanpipe_common.h> | ||
| 105 | #include <linux/if_wanpipe.h> | ||
| 106 | |||
| 107 | |||
| 108 | /*====================================================== | ||
| 109 | * Defines & Macros | ||
| 110 | *=====================================================*/ | ||
| 111 | |||
| 112 | |||
| 113 | #define CMD_OK 0 /* normal firmware return code */ | ||
| 114 | #define CMD_TIMEOUT 0xFF /* firmware command timed out */ | ||
| 115 | #define MAX_CMD_RETRY 10 /* max number of firmware retries */ | ||
| 116 | |||
| 117 | #define X25_CHAN_MTU 4096 /* unfragmented logical channel MTU */ | ||
| 118 | #define X25_HRDHDR_SZ 7 /* max encapsulation header size */ | ||
| 119 | #define X25_CONCT_TMOUT (90*HZ) /* link connection timeout */ | ||
| 120 | #define X25_RECON_TMOUT (10*HZ) /* link connection timeout */ | ||
| 121 | #define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ | ||
| 122 | #define HOLD_DOWN_TIME (30*HZ) /* link hold down time */ | ||
| 123 | #define MAX_BH_BUFF 10 | ||
| 124 | #define M_BIT 0x01 | ||
| 125 | |||
| 126 | //#define PRINT_DEBUG 1 | ||
| 127 | #ifdef PRINT_DEBUG | ||
| 128 | #define DBG_PRINTK(format, a...) printk(format, ## a) | ||
| 129 | #else | ||
| 130 | #define DBG_PRINTK(format, a...) | ||
| 131 | #endif | ||
| 132 | |||
| 133 | #define TMR_INT_ENABLED_POLL_ACTIVE 0x01 | ||
| 134 | #define TMR_INT_ENABLED_POLL_CONNECT_ON 0x02 | ||
| 135 | #define TMR_INT_ENABLED_POLL_CONNECT_OFF 0x04 | ||
| 136 | #define TMR_INT_ENABLED_POLL_DISCONNECT 0x08 | ||
| 137 | #define TMR_INT_ENABLED_CMD_EXEC 0x10 | ||
| 138 | #define TMR_INT_ENABLED_UPDATE 0x20 | ||
| 139 | #define TMR_INT_ENABLED_UDP_PKT 0x40 | ||
| 140 | |||
| 141 | #define MAX_X25_ADDR_SIZE 16 | ||
| 142 | #define MAX_X25_DATA_SIZE 129 | ||
| 143 | #define MAX_X25_FACL_SIZE 110 | ||
| 144 | |||
| 145 | #define TRY_CMD_AGAIN 2 | ||
| 146 | #define DELAY_RESULT 1 | ||
| 147 | #define RETURN_RESULT 0 | ||
| 148 | |||
| 149 | #define DCD(x) (x & 0x03 ? "HIGH" : "LOW") | ||
| 150 | #define CTS(x) (x & 0x05 ? "HIGH" : "LOW") | ||
| 151 | |||
| 152 | |||
| 153 | /* Driver will not write log messages about | ||
| 154 | * modem status if defined.*/ | ||
| 155 | #define MODEM_NOT_LOG 1 | ||
| 156 | |||
| 157 | /*==================================================== | ||
| 158 | * For IPXWAN | ||
| 159 | *===================================================*/ | ||
| 160 | |||
| 161 | #define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) | ||
| 162 | |||
| 163 | |||
| 164 | /*==================================================== | ||
| 165 | * MEMORY DEBUGGING FUNCTION | ||
| 166 | *==================================================== | ||
| 167 | |||
| 168 | #define KMEM_SAFETYZONE 8 | ||
| 169 | |||
| 170 | static void * dbg_kmalloc(unsigned int size, int prio, int line) { | ||
| 171 | int i = 0; | ||
| 172 | void * v = kmalloc(size+sizeof(unsigned int)+2*KMEM_SAFETYZONE*8,prio); | ||
| 173 | char * c1 = v; | ||
| 174 | c1 += sizeof(unsigned int); | ||
| 175 | *((unsigned int *)v) = size; | ||
| 176 | |||
| 177 | for (i = 0; i < KMEM_SAFETYZONE; i++) { | ||
| 178 | c1[0] = 'D'; c1[1] = 'E'; c1[2] = 'A'; c1[3] = 'D'; | ||
| 179 | c1[4] = 'B'; c1[5] = 'E'; c1[6] = 'E'; c1[7] = 'F'; | ||
| 180 | c1 += 8; | ||
| 181 | } | ||
| 182 | c1 += size; | ||
| 183 | for (i = 0; i < KMEM_SAFETYZONE; i++) { | ||
| 184 | c1[0] = 'M'; c1[1] = 'U'; c1[2] = 'N'; c1[3] = 'G'; | ||
| 185 | c1[4] = 'W'; c1[5] = 'A'; c1[6] = 'L'; c1[7] = 'L'; | ||
| 186 | c1 += 8; | ||
| 187 | } | ||
| 188 | v = ((char *)v) + sizeof(unsigned int) + KMEM_SAFETYZONE*8; | ||
| 189 | printk(KERN_INFO "line %d kmalloc(%d,%d) = %p\n",line,size,prio,v); | ||
| 190 | return v; | ||
| 191 | } | ||
| 192 | static void dbg_kfree(void * v, int line) { | ||
| 193 | unsigned int * sp = (unsigned int *)(((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8)); | ||
| 194 | unsigned int size = *sp; | ||
| 195 | char * c1 = ((char *)v) - KMEM_SAFETYZONE*8; | ||
| 196 | int i = 0; | ||
| 197 | for (i = 0; i < KMEM_SAFETYZONE; i++) { | ||
| 198 | if ( c1[0] != 'D' || c1[1] != 'E' || c1[2] != 'A' || c1[3] != 'D' | ||
| 199 | || c1[4] != 'B' || c1[5] != 'E' || c1[6] != 'E' || c1[7] != 'F') { | ||
| 200 | printk(KERN_INFO "kmalloced block at %p has been corrupted (underrun)!\n",v); | ||
| 201 | printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, | ||
| 202 | c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); | ||
| 203 | } | ||
| 204 | c1 += 8; | ||
| 205 | } | ||
| 206 | c1 += size; | ||
| 207 | for (i = 0; i < KMEM_SAFETYZONE; i++) { | ||
| 208 | if ( c1[0] != 'M' || c1[1] != 'U' || c1[2] != 'N' || c1[3] != 'G' | ||
| 209 | || c1[4] != 'W' || c1[5] != 'A' || c1[6] != 'L' || c1[7] != 'L' | ||
| 210 | ) { | ||
| 211 | printk(KERN_INFO "kmalloced block at %p has been corrupted (overrun):\n",v); | ||
| 212 | printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, | ||
| 213 | c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); | ||
| 214 | } | ||
| 215 | c1 += 8; | ||
| 216 | } | ||
| 217 | printk(KERN_INFO "line %d kfree(%p)\n",line,v); | ||
| 218 | v = ((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8); | ||
| 219 | kfree(v); | ||
| 220 | } | ||
| 221 | |||
| 222 | #define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__) | ||
| 223 | #define kfree(x) dbg_kfree(x,__LINE__) | ||
| 224 | |||
| 225 | ==============================================================*/ | ||
| 226 | |||
| 227 | |||
| 228 | |||
| 229 | /*=============================================== | ||
| 230 | * Data Structures | ||
| 231 | *===============================================*/ | ||
| 232 | |||
| 233 | |||
| 234 | /*======================================================== | ||
| 235 | * Name: x25_channel | ||
| 236 | * | ||
| 237 | * Purpose: To hold private informaton for each | ||
| 238 | * logical channel. | ||
| 239 | * | ||
| 240 | * Rationale: Per-channel debugging is possible if each | ||
| 241 | * channel has its own private area. | ||
| 242 | * | ||
| 243 | * Assumptions: | ||
| 244 | * | ||
| 245 | * Description: This is an extention of the struct net_device | ||
| 246 | * we create for each network interface to keep | ||
| 247 | * the rest of X.25 channel-specific data. | ||
| 248 | * | ||
| 249 | * Construct: Typedef | ||
| 250 | */ | ||
| 251 | typedef struct x25_channel | ||
| 252 | { | ||
| 253 | wanpipe_common_t common; /* common area for x25api and socket */ | ||
| 254 | char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ | ||
| 255 | char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */ | ||
| 256 | unsigned tx_pkt_size; | ||
| 257 | unsigned short protocol; /* ethertype, 0 - multiplexed */ | ||
| 258 | char drop_sequence; /* mark sequence for dropping */ | ||
| 259 | unsigned long state_tick; /* time of the last state change */ | ||
| 260 | unsigned idle_timeout; /* sec, before disconnecting */ | ||
| 261 | unsigned long i_timeout_sofar; /* # of sec's we've been idle */ | ||
| 262 | unsigned hold_timeout; /* sec, before re-connecting */ | ||
| 263 | unsigned long tick_counter; /* counter for transmit time out */ | ||
| 264 | char devtint; /* Weather we should dev_tint() */ | ||
| 265 | struct sk_buff* rx_skb; /* receive socket buffer */ | ||
| 266 | struct sk_buff* tx_skb; /* transmit socket buffer */ | ||
| 267 | |||
| 268 | bh_data_t *bh_head; /* Circular buffer for x25api_bh */ | ||
| 269 | unsigned long tq_working; | ||
| 270 | volatile int bh_write; | ||
| 271 | volatile int bh_read; | ||
| 272 | atomic_t bh_buff_used; | ||
| 273 | |||
| 274 | sdla_t* card; /* -> owner */ | ||
| 275 | struct net_device *dev; /* -> bound devce */ | ||
| 276 | |||
| 277 | int ch_idx; | ||
| 278 | unsigned char enable_IPX; | ||
| 279 | unsigned long network_number; | ||
| 280 | struct net_device_stats ifstats; /* interface statistics */ | ||
| 281 | unsigned short transmit_length; | ||
| 282 | unsigned short tx_offset; | ||
| 283 | char transmit_buffer[X25_CHAN_MTU+sizeof(x25api_hdr_t)]; | ||
| 284 | |||
| 285 | if_send_stat_t if_send_stat; | ||
| 286 | rx_intr_stat_t rx_intr_stat; | ||
| 287 | pipe_mgmt_stat_t pipe_mgmt_stat; | ||
| 288 | |||
| 289 | unsigned long router_start_time; /* Router start time in seconds */ | ||
| 290 | unsigned long router_up_time; | ||
| 291 | |||
| 292 | } x25_channel_t; | ||
| 293 | |||
| 294 | /* FIXME Take this out */ | ||
| 295 | |||
| 296 | #ifdef NEX_OLD_CALL_INFO | ||
| 297 | typedef struct x25_call_info | ||
| 298 | { | ||
| 299 | char dest[17]; PACKED;/* ASCIIZ destination address */ | ||
| 300 | char src[17]; PACKED;/* ASCIIZ source address */ | ||
| 301 | char nuser; PACKED;/* number of user data bytes */ | ||
| 302 | unsigned char user[127]; PACKED;/* user data */ | ||
| 303 | char nfacil; PACKED;/* number of facilities */ | ||
| 304 | struct | ||
| 305 | { | ||
| 306 | unsigned char code; PACKED; | ||
| 307 | unsigned char parm; PACKED; | ||
| 308 | } facil[64]; /* facilities */ | ||
| 309 | } x25_call_info_t; | ||
| 310 | #else | ||
| 311 | typedef struct x25_call_info | ||
| 312 | { | ||
| 313 | char dest[MAX_X25_ADDR_SIZE] PACKED;/* ASCIIZ destination address */ | ||
| 314 | char src[MAX_X25_ADDR_SIZE] PACKED;/* ASCIIZ source address */ | ||
| 315 | unsigned char nuser PACKED; | ||
| 316 | unsigned char user[MAX_X25_DATA_SIZE] PACKED;/* user data */ | ||
| 317 | unsigned char nfacil PACKED; | ||
| 318 | unsigned char facil[MAX_X25_FACL_SIZE] PACKED; | ||
| 319 | unsigned short lcn PACKED; | ||
| 320 | } x25_call_info_t; | ||
| 321 | #endif | ||
| 322 | |||
| 323 | |||
| 324 | |||
| 325 | /*=============================================== | ||
| 326 | * Private Function Prototypes | ||
| 327 | *==============================================*/ | ||
| 328 | |||
| 329 | |||
| 330 | /*================================================= | ||
| 331 | * WAN link driver entry points. These are | ||
| 332 | * called by the WAN router module. | ||
| 333 | */ | ||
| 334 | static int update(struct wan_device* wandev); | ||
| 335 | static int new_if(struct wan_device* wandev, struct net_device* dev, | ||
| 336 | wanif_conf_t* conf); | ||
| 337 | static int del_if(struct wan_device* wandev, struct net_device* dev); | ||
| 338 | static void disable_comm (sdla_t* card); | ||
| 339 | static void disable_comm_shutdown(sdla_t *card); | ||
| 340 | |||
| 341 | |||
| 342 | |||
| 343 | /*================================================= | ||
| 344 | * WANPIPE-specific entry points | ||
| 345 | */ | ||
| 346 | static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data); | ||
| 347 | static void x25api_bh(struct net_device *dev); | ||
| 348 | static int x25api_bh_cleanup(struct net_device *dev); | ||
| 349 | static int bh_enqueue(struct net_device *dev, struct sk_buff *skb); | ||
| 350 | |||
| 351 | |||
| 352 | /*================================================= | ||
| 353 | * Network device interface | ||
| 354 | */ | ||
| 355 | static int if_init(struct net_device* dev); | ||
| 356 | static int if_open(struct net_device* dev); | ||
| 357 | static int if_close(struct net_device* dev); | ||
| 358 | static int if_header(struct sk_buff* skb, struct net_device* dev, | ||
| 359 | unsigned short type, void* daddr, void* saddr, unsigned len); | ||
| 360 | static int if_rebuild_hdr (struct sk_buff* skb); | ||
| 361 | static int if_send(struct sk_buff* skb, struct net_device* dev); | ||
| 362 | static struct net_device_stats *if_stats(struct net_device* dev); | ||
| 363 | |||
| 364 | static void if_tx_timeout(struct net_device *dev); | ||
| 365 | |||
| 366 | /*================================================= | ||
| 367 | * Interrupt handlers | ||
| 368 | */ | ||
| 369 | static void wpx_isr (sdla_t *); | ||
| 370 | static void rx_intr (sdla_t *); | ||
| 371 | static void tx_intr (sdla_t *); | ||
| 372 | static void status_intr (sdla_t *); | ||
| 373 | static void event_intr (sdla_t *); | ||
| 374 | static void spur_intr (sdla_t *); | ||
| 375 | static void timer_intr (sdla_t *); | ||
| 376 | |||
| 377 | static int tx_intr_send(sdla_t *card, struct net_device *dev); | ||
| 378 | static struct net_device *move_dev_to_next(sdla_t *card, | ||
| 379 | struct net_device *dev); | ||
| 380 | |||
| 381 | /*================================================= | ||
| 382 | * Background polling routines | ||
| 383 | */ | ||
| 384 | static void wpx_poll (sdla_t* card); | ||
| 385 | static void poll_disconnected (sdla_t* card); | ||
| 386 | static void poll_connecting (sdla_t* card); | ||
| 387 | static void poll_active (sdla_t* card); | ||
| 388 | static void trigger_x25_poll(sdla_t *card); | ||
| 389 | static void x25_timer_routine(unsigned long data); | ||
| 390 | |||
| 391 | |||
| 392 | |||
| 393 | /*================================================= | ||
| 394 | * X.25 firmware interface functions | ||
| 395 | */ | ||
| 396 | static int x25_get_version (sdla_t* card, char* str); | ||
| 397 | static int x25_configure (sdla_t* card, TX25Config* conf); | ||
| 398 | static int hdlc_configure (sdla_t* card, TX25Config* conf); | ||
| 399 | static int set_hdlc_level (sdla_t* card); | ||
| 400 | static int x25_get_err_stats (sdla_t* card); | ||
| 401 | static int x25_get_stats (sdla_t* card); | ||
| 402 | static int x25_set_intr_mode (sdla_t* card, int mode); | ||
| 403 | static int x25_close_hdlc (sdla_t* card); | ||
| 404 | static int x25_open_hdlc (sdla_t* card); | ||
| 405 | static int x25_setup_hdlc (sdla_t* card); | ||
| 406 | static int x25_set_dtr (sdla_t* card, int dtr); | ||
| 407 | static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan); | ||
| 408 | static int x25_place_call (sdla_t* card, x25_channel_t* chan); | ||
| 409 | static int x25_accept_call (sdla_t* card, int lcn, int qdm); | ||
| 410 | static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn); | ||
| 411 | static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf); | ||
| 412 | static int x25_fetch_events (sdla_t* card); | ||
| 413 | static int x25_error (sdla_t* card, int err, int cmd, int lcn); | ||
| 414 | |||
| 415 | /*================================================= | ||
| 416 | * X.25 asynchronous event handlers | ||
| 417 | */ | ||
| 418 | static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); | ||
| 419 | static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); | ||
| 420 | static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); | ||
| 421 | static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); | ||
| 422 | static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); | ||
| 423 | |||
| 424 | |||
| 425 | /*================================================= | ||
| 426 | * Miscellaneous functions | ||
| 427 | */ | ||
| 428 | static int connect (sdla_t* card); | ||
| 429 | static int disconnect (sdla_t* card); | ||
| 430 | static struct net_device* get_dev_by_lcn(struct wan_device* wandev, | ||
| 431 | unsigned lcn); | ||
| 432 | static int chan_connect(struct net_device* dev); | ||
| 433 | static int chan_disc(struct net_device* dev); | ||
| 434 | static void set_chan_state(struct net_device* dev, int state); | ||
| 435 | static int chan_send(struct net_device *dev, void* buff, unsigned data_len, | ||
| 436 | unsigned char tx_intr); | ||
| 437 | static unsigned char bps_to_speed_code (unsigned long bps); | ||
| 438 | static unsigned int dec_to_uint (unsigned char* str, int len); | ||
| 439 | static unsigned int hex_to_uint (unsigned char*, int); | ||
| 440 | static void parse_call_info (unsigned char*, x25_call_info_t*); | ||
| 441 | static struct net_device *find_channel(sdla_t *card, unsigned lcn); | ||
| 442 | static void bind_lcn_to_dev(sdla_t *card, struct net_device *dev, unsigned lcn); | ||
| 443 | static void setup_for_delayed_transmit(struct net_device *dev, | ||
| 444 | void *buf, unsigned len); | ||
| 445 | |||
| 446 | |||
| 447 | /*================================================= | ||
| 448 | * X25 API Functions | ||
| 449 | */ | ||
| 450 | static int wanpipe_pull_data_in_skb(sdla_t *card, struct net_device *dev, | ||
| 451 | struct sk_buff **); | ||
| 452 | static void timer_intr_exec(sdla_t *, unsigned char); | ||
| 453 | static int execute_delayed_cmd(sdla_t *card, struct net_device *dev, | ||
| 454 | mbox_cmd_t *usr_cmd, char bad_cmd); | ||
| 455 | static int api_incoming_call (sdla_t*, TX25Mbox *, int); | ||
| 456 | static int alloc_and_init_skb_buf (sdla_t *,struct sk_buff **, int); | ||
| 457 | static void send_delayed_cmd_result(sdla_t *card, struct net_device *dev, | ||
| 458 | TX25Mbox* mbox); | ||
| 459 | static int clear_confirm_event (sdla_t *, TX25Mbox*); | ||
| 460 | static void send_oob_msg (sdla_t *card, struct net_device *dev, TX25Mbox *mbox); | ||
| 461 | static int timer_intr_cmd_exec(sdla_t *card); | ||
| 462 | static void api_oob_event (sdla_t *card,TX25Mbox *mbox); | ||
| 463 | static int check_bad_command(sdla_t *card, struct net_device *dev); | ||
| 464 | static int channel_disconnect(sdla_t* card, struct net_device *dev); | ||
| 465 | static void hdlc_link_down (sdla_t*); | ||
| 466 | |||
| 467 | /*================================================= | ||
| 468 | * XPIPEMON Functions | ||
| 469 | */ | ||
| 470 | static int process_udp_mgmt_pkt(sdla_t *); | ||
| 471 | static int udp_pkt_type( struct sk_buff *, sdla_t*); | ||
| 472 | static int reply_udp( unsigned char *, unsigned int); | ||
| 473 | static void init_x25_channel_struct( x25_channel_t *); | ||
| 474 | static void init_global_statistics( sdla_t *); | ||
| 475 | static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t *card, | ||
| 476 | struct net_device *dev, | ||
| 477 | struct sk_buff *skb, int lcn); | ||
| 478 | static unsigned short calc_checksum (char *, int); | ||
| 479 | |||
| 480 | |||
| 481 | |||
| 482 | /*================================================= | ||
| 483 | * IPX functions | ||
| 484 | */ | ||
| 485 | static void switch_net_numbers(unsigned char *, unsigned long, unsigned char); | ||
| 486 | static int handle_IPXWAN(unsigned char *, char *, unsigned char , | ||
| 487 | unsigned long , unsigned short ); | ||
| 488 | |||
| 489 | extern void disable_irq(unsigned int); | ||
| 490 | extern void enable_irq(unsigned int); | ||
| 491 | |||
| 492 | static void S508_S514_lock(sdla_t *, unsigned long *); | ||
| 493 | static void S508_S514_unlock(sdla_t *, unsigned long *); | ||
| 494 | |||
| 495 | |||
| 496 | /*================================================= | ||
| 497 | * Global Variables | ||
| 498 | *=================================================*/ | ||
| 499 | |||
| 500 | |||
| 501 | |||
| 502 | /*================================================= | ||
| 503 | * Public Functions | ||
| 504 | *=================================================*/ | ||
| 505 | |||
| 506 | |||
| 507 | |||
| 508 | |||
| 509 | /*=================================================================== | ||
| 510 | * wpx_init: X.25 Protocol Initialization routine. | ||
| 511 | * | ||
| 512 | * Purpose: To initialize the protocol/firmware. | ||
| 513 | * | ||
| 514 | * Rationale: This function is called by setup() function, in | ||
| 515 | * sdlamain.c, to dynamically setup the x25 protocol. | ||
| 516 | * This is the first protocol specific function, which | ||
| 517 | * executes once on startup. | ||
| 518 | * | ||
| 519 | * Description: This procedure initializes the x25 firmware and | ||
| 520 | * sets up the mailbox, transmit and receive buffer | ||
| 521 | * pointers. It also initializes all debugging structures | ||
| 522 | * and sets up the X25 environment. | ||
| 523 | * | ||
| 524 | * Sets up hardware options defined by user in [wanpipe#] | ||
| 525 | * section of wanpipe#.conf configuration file. | ||
| 526 | * | ||
| 527 | * At this point adapter is completely initialized | ||
| 528 | * and X.25 firmware is running. | ||
| 529 | * o read firmware version (to make sure it's alive) | ||
| 530 | * o configure adapter | ||
| 531 | * o initialize protocol-specific fields of the | ||
| 532 | * adapter data space. | ||
| 533 | * | ||
| 534 | * Called by: setup() function in sdlamain.c | ||
| 535 | * | ||
| 536 | * Assumptions: None | ||
| 537 | * | ||
| 538 | * Warnings: None | ||
| 539 | * | ||
| 540 | * Return: 0 o.k. | ||
| 541 | * < 0 failure. | ||
| 542 | */ | ||
| 543 | |||
| 544 | int wpx_init (sdla_t* card, wandev_conf_t* conf) | ||
| 545 | { | ||
| 546 | union{ | ||
| 547 | char str[80]; | ||
| 548 | TX25Config cfg; | ||
| 549 | } u; | ||
| 550 | |||
| 551 | /* Verify configuration ID */ | ||
| 552 | if (conf->config_id != WANCONFIG_X25){ | ||
| 553 | printk(KERN_INFO "%s: invalid configuration ID %u!\n", | ||
| 554 | card->devname, conf->config_id) | ||
| 555 | ; | ||
| 556 | return -EINVAL; | ||
| 557 | } | ||
| 558 | |||
| 559 | /* Initialize protocol-specific fields */ | ||
| 560 | card->mbox = (void*)(card->hw.dpmbase + X25_MBOX_OFFS); | ||
| 561 | card->rxmb = (void*)(card->hw.dpmbase + X25_RXMBOX_OFFS); | ||
| 562 | card->flags = (void*)(card->hw.dpmbase + X25_STATUS_OFFS); | ||
| 563 | |||
| 564 | /* Initialize for S514 Card */ | ||
| 565 | if(card->hw.type == SDLA_S514) { | ||
| 566 | card->mbox += X25_MB_VECTOR; | ||
| 567 | card->flags += X25_MB_VECTOR; | ||
| 568 | card->rxmb += X25_MB_VECTOR; | ||
| 569 | } | ||
| 570 | |||
| 571 | |||
| 572 | /* Read firmware version. Note that when adapter initializes, it | ||
| 573 | * clears the mailbox, so it may appear that the first command was | ||
| 574 | * executed successfully when in fact it was merely erased. To work | ||
| 575 | * around this, we execute the first command twice. | ||
| 576 | */ | ||
| 577 | if (x25_get_version(card, NULL) || x25_get_version(card, u.str)) | ||
| 578 | return -EIO; | ||
| 579 | |||
| 580 | |||
| 581 | /* X25 firmware can run ether in X25 or LAPB HDLC mode. | ||
| 582 | * Check the user defined option and configure accordingly */ | ||
| 583 | if (conf->u.x25.LAPB_hdlc_only == WANOPT_YES){ | ||
| 584 | if (set_hdlc_level(card) != CMD_OK){ | ||
| 585 | return -EIO; | ||
| 586 | }else{ | ||
| 587 | printk(KERN_INFO "%s: running LAP_B HDLC firmware v%s\n", | ||
| 588 | card->devname, u.str); | ||
| 589 | } | ||
| 590 | card->u.x.LAPB_hdlc = 1; | ||
| 591 | }else{ | ||
| 592 | printk(KERN_INFO "%s: running X.25 firmware v%s\n", | ||
| 593 | card->devname, u.str); | ||
| 594 | card->u.x.LAPB_hdlc = 0; | ||
| 595 | } | ||
| 596 | |||
| 597 | /* Configure adapter. Here we set resonable defaults, then parse | ||
| 598 | * device configuration structure and set configuration options. | ||
| 599 | * Most configuration options are verified and corrected (if | ||
| 600 | * necessary) since we can't rely on the adapter to do so. | ||
| 601 | */ | ||
| 602 | memset(&u.cfg, 0, sizeof(u.cfg)); | ||
| 603 | u.cfg.t1 = 3; | ||
| 604 | u.cfg.n2 = 10; | ||
| 605 | u.cfg.autoHdlc = 1; /* automatic HDLC connection */ | ||
| 606 | u.cfg.hdlcWindow = 7; | ||
| 607 | u.cfg.pktWindow = 2; | ||
| 608 | u.cfg.station = 1; /* DTE */ | ||
| 609 | u.cfg.options = 0x0090; /* disable D-bit pragmatics */ | ||
| 610 | u.cfg.ccittCompat = 1988; | ||
| 611 | u.cfg.t10t20 = 30; | ||
| 612 | u.cfg.t11t21 = 30; | ||
| 613 | u.cfg.t12t22 = 30; | ||
| 614 | u.cfg.t13t23 = 30; | ||
| 615 | u.cfg.t16t26 = 30; | ||
| 616 | u.cfg.t28 = 30; | ||
| 617 | u.cfg.r10r20 = 5; | ||
| 618 | u.cfg.r12r22 = 5; | ||
| 619 | u.cfg.r13r23 = 5; | ||
| 620 | u.cfg.responseOpt = 1; /* RR's after every packet */ | ||
| 621 | |||
| 622 | if (card->u.x.LAPB_hdlc){ | ||
| 623 | u.cfg.hdlcMTU = 1027; | ||
| 624 | } | ||
| 625 | |||
| 626 | if (conf->u.x25.x25_conf_opt){ | ||
| 627 | u.cfg.options = conf->u.x25.x25_conf_opt; | ||
| 628 | } | ||
| 629 | |||
| 630 | if (conf->clocking != WANOPT_EXTERNAL) | ||
| 631 | u.cfg.baudRate = bps_to_speed_code(conf->bps); | ||
| 632 | |||
| 633 | if (conf->station != WANOPT_DTE){ | ||
| 634 | u.cfg.station = 0; /* DCE mode */ | ||
| 635 | } | ||
| 636 | |||
| 637 | if (conf->interface != WANOPT_RS232 ){ | ||
| 638 | u.cfg.hdlcOptions |= 0x80; /* V35 mode */ | ||
| 639 | } | ||
| 640 | |||
| 641 | /* adjust MTU */ | ||
| 642 | if (!conf->mtu || (conf->mtu >= 1024)) | ||
| 643 | card->wandev.mtu = 1024; | ||
| 644 | else if (conf->mtu >= 512) | ||
| 645 | card->wandev.mtu = 512; | ||
| 646 | else if (conf->mtu >= 256) | ||
| 647 | card->wandev.mtu = 256; | ||
| 648 | else if (conf->mtu >= 128) | ||
| 649 | card->wandev.mtu = 128; | ||
| 650 | else | ||
| 651 | card->wandev.mtu = 64; | ||
| 652 | |||
| 653 | u.cfg.defPktSize = u.cfg.pktMTU = card->wandev.mtu; | ||
| 654 | |||
| 655 | if (conf->u.x25.hi_pvc){ | ||
| 656 | card->u.x.hi_pvc = min_t(unsigned int, conf->u.x25.hi_pvc, MAX_LCN_NUM); | ||
| 657 | card->u.x.lo_pvc = min_t(unsigned int, conf->u.x25.lo_pvc, card->u.x.hi_pvc); | ||
| 658 | } | ||
| 659 | |||
| 660 | if (conf->u.x25.hi_svc){ | ||
| 661 | card->u.x.hi_svc = min_t(unsigned int, conf->u.x25.hi_svc, MAX_LCN_NUM); | ||
| 662 | card->u.x.lo_svc = min_t(unsigned int, conf->u.x25.lo_svc, card->u.x.hi_svc); | ||
| 663 | } | ||
| 664 | |||
| 665 | /* Figure out the total number of channels to configure */ | ||
| 666 | card->u.x.num_of_ch = 0; | ||
| 667 | if (card->u.x.hi_svc != 0){ | ||
| 668 | card->u.x.num_of_ch = (card->u.x.hi_svc - card->u.x.lo_svc) + 1; | ||
| 669 | } | ||
| 670 | if (card->u.x.hi_pvc != 0){ | ||
| 671 | card->u.x.num_of_ch += (card->u.x.hi_pvc - card->u.x.lo_pvc) + 1; | ||
| 672 | } | ||
| 673 | |||
| 674 | if (card->u.x.num_of_ch == 0){ | ||
| 675 | printk(KERN_INFO "%s: ERROR, Minimum number of PVC/SVC channels is 1 !\n" | ||
| 676 | "%s: Please set the Lowest/Highest PVC/SVC values !\n", | ||
| 677 | card->devname,card->devname); | ||
| 678 | return -ECHRNG; | ||
| 679 | } | ||
| 680 | |||
| 681 | u.cfg.loPVC = card->u.x.lo_pvc; | ||
| 682 | u.cfg.hiPVC = card->u.x.hi_pvc; | ||
| 683 | u.cfg.loTwoWaySVC = card->u.x.lo_svc; | ||
| 684 | u.cfg.hiTwoWaySVC = card->u.x.hi_svc; | ||
| 685 | |||
| 686 | if (conf->u.x25.hdlc_window) | ||
| 687 | u.cfg.hdlcWindow = min_t(unsigned int, conf->u.x25.hdlc_window, 7); | ||
| 688 | if (conf->u.x25.pkt_window) | ||
| 689 | u.cfg.pktWindow = min_t(unsigned int, conf->u.x25.pkt_window, 7); | ||
| 690 | |||
| 691 | if (conf->u.x25.t1) | ||
| 692 | u.cfg.t1 = min_t(unsigned int, conf->u.x25.t1, 30); | ||
| 693 | if (conf->u.x25.t2) | ||
| 694 | u.cfg.t2 = min_t(unsigned int, conf->u.x25.t2, 29); | ||
| 695 | if (conf->u.x25.t4) | ||
| 696 | u.cfg.t4 = min_t(unsigned int, conf->u.x25.t4, 240); | ||
| 697 | if (conf->u.x25.n2) | ||
| 698 | u.cfg.n2 = min_t(unsigned int, conf->u.x25.n2, 30); | ||
| 699 | |||
| 700 | if (conf->u.x25.t10_t20) | ||
| 701 | u.cfg.t10t20 = min_t(unsigned int, conf->u.x25.t10_t20,255); | ||
| 702 | if (conf->u.x25.t11_t21) | ||
| 703 | u.cfg.t11t21 = min_t(unsigned int, conf->u.x25.t11_t21,255); | ||
| 704 | if (conf->u.x25.t12_t22) | ||
| 705 | u.cfg.t12t22 = min_t(unsigned int, conf->u.x25.t12_t22,255); | ||
| 706 | if (conf->u.x25.t13_t23) | ||
| 707 | u.cfg.t13t23 = min_t(unsigned int, conf->u.x25.t13_t23,255); | ||
| 708 | if (conf->u.x25.t16_t26) | ||
| 709 | u.cfg.t16t26 = min_t(unsigned int, conf->u.x25.t16_t26, 255); | ||
| 710 | if (conf->u.x25.t28) | ||
| 711 | u.cfg.t28 = min_t(unsigned int, conf->u.x25.t28, 255); | ||
| 712 | |||
| 713 | if (conf->u.x25.r10_r20) | ||
| 714 | u.cfg.r10r20 = min_t(unsigned int, conf->u.x25.r10_r20,250); | ||
| 715 | if (conf->u.x25.r12_r22) | ||
| 716 | u.cfg.r12r22 = min_t(unsigned int, conf->u.x25.r12_r22,250); | ||
| 717 | if (conf->u.x25.r13_r23) | ||
| 718 | u.cfg.r13r23 = min_t(unsigned int, conf->u.x25.r13_r23,250); | ||
| 719 | |||
| 720 | |||
| 721 | if (conf->u.x25.ccitt_compat) | ||
| 722 | u.cfg.ccittCompat = conf->u.x25.ccitt_compat; | ||
| 723 | |||
| 724 | /* initialize adapter */ | ||
| 725 | if (card->u.x.LAPB_hdlc){ | ||
| 726 | if (hdlc_configure(card, &u.cfg) != CMD_OK) | ||
| 727 | return -EIO; | ||
| 728 | }else{ | ||
| 729 | if (x25_configure(card, &u.cfg) != CMD_OK) | ||
| 730 | return -EIO; | ||
| 731 | } | ||
| 732 | |||
| 733 | if ((x25_close_hdlc(card) != CMD_OK) || /* close HDLC link */ | ||
| 734 | (x25_set_dtr(card, 0) != CMD_OK)) /* drop DTR */ | ||
| 735 | return -EIO; | ||
| 736 | |||
| 737 | /* Initialize protocol-specific fields of adapter data space */ | ||
| 738 | card->wandev.bps = conf->bps; | ||
| 739 | card->wandev.interface = conf->interface; | ||
| 740 | card->wandev.clocking = conf->clocking; | ||
| 741 | card->wandev.station = conf->station; | ||
| 742 | card->isr = &wpx_isr; | ||
| 743 | card->poll = NULL; //&wpx_poll; | ||
| 744 | card->disable_comm = &disable_comm; | ||
| 745 | card->exec = &wpx_exec; | ||
| 746 | card->wandev.update = &update; | ||
| 747 | card->wandev.new_if = &new_if; | ||
| 748 | card->wandev.del_if = &del_if; | ||
| 749 | |||
| 750 | /* WARNING: This function cannot exit with an error | ||
| 751 | * after the change of state */ | ||
| 752 | card->wandev.state = WAN_DISCONNECTED; | ||
| 753 | |||
| 754 | card->wandev.enable_tx_int = 0; | ||
| 755 | card->irq_dis_if_send_count = 0; | ||
| 756 | card->irq_dis_poll_count = 0; | ||
| 757 | card->u.x.tx_dev = NULL; | ||
| 758 | card->u.x.no_dev = 0; | ||
| 759 | |||
| 760 | |||
| 761 | /* Configure for S514 PCI Card */ | ||
| 762 | if (card->hw.type == SDLA_S514) { | ||
| 763 | card->u.x.hdlc_buf_status = | ||
| 764 | (volatile unsigned char *) | ||
| 765 | (card->hw.dpmbase + X25_MB_VECTOR+ X25_MISC_HDLC_BITS); | ||
| 766 | }else{ | ||
| 767 | card->u.x.hdlc_buf_status = | ||
| 768 | (volatile unsigned char *)(card->hw.dpmbase + X25_MISC_HDLC_BITS); | ||
| 769 | } | ||
| 770 | |||
| 771 | card->u.x.poll_device=NULL; | ||
| 772 | card->wandev.udp_port = conf->udp_port; | ||
| 773 | |||
| 774 | /* Enable or disable call setup logging */ | ||
| 775 | if (conf->u.x25.logging == WANOPT_YES){ | ||
| 776 | printk(KERN_INFO "%s: Enabling Call Logging.\n", | ||
| 777 | card->devname); | ||
| 778 | card->u.x.logging = 1; | ||
| 779 | }else{ | ||
| 780 | card->u.x.logging = 0; | ||
| 781 | } | ||
| 782 | |||
| 783 | /* Enable or disable modem status reporting */ | ||
| 784 | if (conf->u.x25.oob_on_modem == WANOPT_YES){ | ||
| 785 | printk(KERN_INFO "%s: Enabling OOB on Modem change.\n", | ||
| 786 | card->devname); | ||
| 787 | card->u.x.oob_on_modem = 1; | ||
| 788 | }else{ | ||
| 789 | card->u.x.oob_on_modem = 0; | ||
| 790 | } | ||
| 791 | |||
| 792 | init_global_statistics(card); | ||
| 793 | |||
| 794 | INIT_WORK(&card->u.x.x25_poll_work, (void *)wpx_poll, card); | ||
| 795 | |||
| 796 | init_timer(&card->u.x.x25_timer); | ||
| 797 | card->u.x.x25_timer.data = (unsigned long)card; | ||
| 798 | card->u.x.x25_timer.function = x25_timer_routine; | ||
| 799 | |||
| 800 | return 0; | ||
| 801 | } | ||
| 802 | |||
| 803 | /*========================================================= | ||
| 804 | * WAN Device Driver Entry Points | ||
| 805 | *========================================================*/ | ||
| 806 | |||
| 807 | /*============================================================ | ||
| 808 | * Name: update(), Update device status & statistics. | ||
| 809 | * | ||
| 810 | * Purpose: To provide debugging and statitical | ||
| 811 | * information to the /proc file system. | ||
| 812 | * /proc/net/wanrouter/wanpipe# | ||
| 813 | * | ||
| 814 | * Rationale: The /proc file system is used to collect | ||
| 815 | * information about the kernel and drivers. | ||
| 816 | * Using the /proc file system the user | ||
| 817 | * can see exactly what the sangoma drivers are | ||
| 818 | * doing. And in what state they are in. | ||
| 819 | * | ||
| 820 | * Description: Collect all driver statistical information | ||
| 821 | * and pass it to the top laywer. | ||
| 822 | * | ||
| 823 | * Since we have to execute a debugging command, | ||
| 824 | * to obtain firmware statitics, we trigger a | ||
| 825 | * UPDATE function within the timer interrtup. | ||
| 826 | * We wait until the timer update is complete. | ||
| 827 | * Once complete return the appropriate return | ||
| 828 | * code to indicate that the update was successful. | ||
| 829 | * | ||
| 830 | * Called by: device_stat() in wanmain.c | ||
| 831 | * | ||
| 832 | * Assumptions: | ||
| 833 | * | ||
| 834 | * Warnings: This function will degrade the performance | ||
| 835 | * of the router, since it uses the mailbox. | ||
| 836 | * | ||
| 837 | * Return: 0 OK | ||
| 838 | * <0 Failed (or busy). | ||
| 839 | */ | ||
| 840 | |||
| 841 | static int update(struct wan_device* wandev) | ||
| 842 | { | ||
| 843 | volatile sdla_t* card; | ||
| 844 | TX25Status* status; | ||
| 845 | unsigned long timeout; | ||
| 846 | |||
| 847 | /* sanity checks */ | ||
| 848 | if ((wandev == NULL) || (wandev->private == NULL)) | ||
| 849 | return -EFAULT; | ||
| 850 | |||
| 851 | if (wandev->state == WAN_UNCONFIGURED) | ||
| 852 | return -ENODEV; | ||
| 853 | |||
| 854 | if (test_bit(SEND_CRIT, (void*)&wandev->critical)) | ||
| 855 | return -EAGAIN; | ||
| 856 | |||
| 857 | if (!wandev->dev) | ||
| 858 | return -ENODEV; | ||
| 859 | |||
| 860 | card = wandev->private; | ||
| 861 | status = card->flags; | ||
| 862 | |||
| 863 | card->u.x.timer_int_enabled |= TMR_INT_ENABLED_UPDATE; | ||
| 864 | status->imask |= INTR_ON_TIMER; | ||
| 865 | timeout = jiffies; | ||
| 866 | |||
| 867 | for (;;){ | ||
| 868 | if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_UPDATE)){ | ||
| 869 | break; | ||
| 870 | } | ||
| 871 | if (time_after(jiffies, timeout + 1*HZ)){ | ||
| 872 | card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; | ||
| 873 | return -EAGAIN; | ||
| 874 | } | ||
| 875 | } | ||
| 876 | return 0; | ||
| 877 | } | ||
| 878 | |||
| 879 | |||
| 880 | /*=================================================================== | ||
| 881 | * Name: new_if | ||
| 882 | * | ||
| 883 | * Purpose: To allocate and initialize resources for a | ||
| 884 | * new logical channel. | ||
| 885 | * | ||
| 886 | * Rationale: A new channel can be added dynamically via | ||
| 887 | * ioctl call. | ||
| 888 | * | ||
| 889 | * Description: Allocate a private channel structure, x25_channel_t. | ||
| 890 | * Parse the user interface options from wanpipe#.conf | ||
| 891 | * configuration file. | ||
| 892 | * Bind the private are into the network device private | ||
| 893 | * area pointer (dev->priv). | ||
| 894 | * Prepare the network device structure for registration. | ||
| 895 | * | ||
| 896 | * Called by: ROUTER_IFNEW Ioctl call, from wanrouter_ioctl() | ||
| 897 | * (wanmain.c) | ||
| 898 | * | ||
| 899 | * Assumptions: None | ||
| 900 | * | ||
| 901 | * Warnings: None | ||
| 902 | * | ||
| 903 | * Return: 0 Ok | ||
| 904 | * <0 Failed (channel will not be created) | ||
| 905 | */ | ||
| 906 | static int new_if(struct wan_device* wandev, struct net_device* dev, | ||
| 907 | wanif_conf_t* conf) | ||
| 908 | { | ||
| 909 | sdla_t* card = wandev->private; | ||
| 910 | x25_channel_t* chan; | ||
| 911 | int err = 0; | ||
| 912 | |||
| 913 | if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)){ | ||
| 914 | printk(KERN_INFO "%s: invalid interface name!\n", | ||
| 915 | card->devname); | ||
| 916 | return -EINVAL; | ||
| 917 | } | ||
| 918 | |||
| 919 | if(card->wandev.new_if_cnt++ > 0 && card->u.x.LAPB_hdlc) { | ||
| 920 | printk(KERN_INFO "%s: Error: Running LAPB HDLC Mode !\n", | ||
| 921 | card->devname); | ||
| 922 | printk(KERN_INFO | ||
| 923 | "%s: Maximum number of network interfaces must be one !\n", | ||
| 924 | card->devname); | ||
| 925 | return -EEXIST; | ||
| 926 | } | ||
| 927 | |||
| 928 | /* allocate and initialize private data */ | ||
| 929 | chan = kmalloc(sizeof(x25_channel_t), GFP_ATOMIC); | ||
| 930 | if (chan == NULL){ | ||
| 931 | return -ENOMEM; | ||
| 932 | } | ||
| 933 | |||
| 934 | memset(chan, 0, sizeof(x25_channel_t)); | ||
| 935 | |||
| 936 | /* Bug Fix: Seg Err on PVC startup | ||
| 937 | * It must be here since bind_lcn_to_dev expects | ||
| 938 | * it bellow */ | ||
| 939 | dev->priv = chan; | ||
| 940 | |||
| 941 | strcpy(chan->name, conf->name); | ||
| 942 | chan->card = card; | ||
| 943 | chan->dev = dev; | ||
| 944 | chan->common.sk = NULL; | ||
| 945 | chan->common.func = NULL; | ||
| 946 | chan->common.rw_bind = 0; | ||
| 947 | chan->tx_skb = chan->rx_skb = NULL; | ||
| 948 | |||
| 949 | /* verify media address */ | ||
| 950 | if (conf->addr[0] == '@'){ /* SVC */ | ||
| 951 | chan->common.svc = 1; | ||
| 952 | strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ); | ||
| 953 | |||
| 954 | /* Set channel timeouts (default if not specified) */ | ||
| 955 | chan->idle_timeout = (conf->idle_timeout) ? | ||
| 956 | conf->idle_timeout : 90; | ||
| 957 | chan->hold_timeout = (conf->hold_timeout) ? | ||
| 958 | conf->hold_timeout : 10; | ||
| 959 | |||
| 960 | }else if (isdigit(conf->addr[0])){ /* PVC */ | ||
| 961 | int lcn = dec_to_uint(conf->addr, 0); | ||
| 962 | |||
| 963 | if ((lcn >= card->u.x.lo_pvc) && (lcn <= card->u.x.hi_pvc)){ | ||
| 964 | bind_lcn_to_dev (card, dev, lcn); | ||
| 965 | }else{ | ||
| 966 | printk(KERN_ERR | ||
| 967 | "%s: PVC %u is out of range on interface %s!\n", | ||
| 968 | wandev->name, lcn, chan->name); | ||
| 969 | err = -EINVAL; | ||
| 970 | } | ||
| 971 | }else{ | ||
| 972 | printk(KERN_ERR | ||
| 973 | "%s: invalid media address on interface %s!\n", | ||
| 974 | wandev->name, chan->name); | ||
| 975 | err = -EINVAL; | ||
| 976 | } | ||
| 977 | |||
| 978 | if(strcmp(conf->usedby, "WANPIPE") == 0){ | ||
| 979 | printk(KERN_INFO "%s: Running in WANPIPE mode %s\n", | ||
| 980 | wandev->name, chan->name); | ||
| 981 | chan->common.usedby = WANPIPE; | ||
| 982 | chan->protocol = htons(ETH_P_IP); | ||
| 983 | |||
| 984 | }else if(strcmp(conf->usedby, "API") == 0){ | ||
| 985 | chan->common.usedby = API; | ||
| 986 | printk(KERN_INFO "%s: Running in API mode %s\n", | ||
| 987 | wandev->name, chan->name); | ||
| 988 | chan->protocol = htons(X25_PROT); | ||
| 989 | } | ||
| 990 | |||
| 991 | |||
| 992 | if (err){ | ||
| 993 | kfree(chan); | ||
| 994 | dev->priv = NULL; | ||
| 995 | return err; | ||
| 996 | } | ||
| 997 | |||
| 998 | chan->enable_IPX = conf->enable_IPX; | ||
| 999 | |||
| 1000 | if (chan->enable_IPX) | ||
| 1001 | chan->protocol = htons(ETH_P_IPX); | ||
| 1002 | |||
| 1003 | if (conf->network_number) | ||
| 1004 | chan->network_number = conf->network_number; | ||
| 1005 | else | ||
| 1006 | chan->network_number = 0xDEADBEEF; | ||
| 1007 | |||
| 1008 | /* prepare network device data space for registration */ | ||
| 1009 | strcpy(dev->name,chan->name); | ||
| 1010 | |||
| 1011 | dev->init = &if_init; | ||
| 1012 | |||
| 1013 | init_x25_channel_struct(chan); | ||
| 1014 | |||
| 1015 | return 0; | ||
| 1016 | } | ||
| 1017 | |||
| 1018 | /*=================================================================== | ||
| 1019 | * Name: del_if(), Remove a logical channel. | ||
| 1020 | * | ||
| 1021 | * Purpose: To dynamically remove a logical channel. | ||
| 1022 | * | ||
| 1023 | * Rationale: Each logical channel should be dynamically | ||
| 1024 | * removable. This functin is called by an | ||
| 1025 | * IOCTL_IFDEL ioctl call or shutdown(). | ||
| 1026 | * | ||
| 1027 | * Description: Do nothing. | ||
| 1028 | * | ||
| 1029 | * Called by: IOCTL_IFDEL : wanrouter_ioctl() from wanmain.c | ||
| 1030 | * shutdown() from sdlamain.c | ||
| 1031 | * | ||
| 1032 | * Assumptions: | ||
| 1033 | * | ||
| 1034 | * Warnings: | ||
| 1035 | * | ||
| 1036 | * Return: 0 Ok. Void function. | ||
| 1037 | */ | ||
| 1038 | |||
| 1039 | //FIXME Del IF Should be taken out now. | ||
| 1040 | |||
| 1041 | static int del_if(struct wan_device* wandev, struct net_device* dev) | ||
| 1042 | { | ||
| 1043 | return 0; | ||
| 1044 | } | ||
| 1045 | |||
| 1046 | |||
| 1047 | /*============================================================ | ||
| 1048 | * Name: wpx_exec | ||
| 1049 | * | ||
| 1050 | * Description: Execute adapter interface command. | ||
| 1051 | * This option is currently dissabled. | ||
| 1052 | *===========================================================*/ | ||
| 1053 | |||
| 1054 | static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data) | ||
| 1055 | { | ||
| 1056 | return 0; | ||
| 1057 | } | ||
| 1058 | |||
| 1059 | /*============================================================ | ||
| 1060 | * Name: disable_comm | ||
| 1061 | * | ||
| 1062 | * Description: Disable communications during shutdown. | ||
| 1063 | * Dont check return code because there is | ||
| 1064 | * nothing we can do about it. | ||
| 1065 | * | ||
| 1066 | * Warning: Dev and private areas are gone at this point. | ||
| 1067 | *===========================================================*/ | ||
| 1068 | |||
| 1069 | static void disable_comm(sdla_t* card) | ||
| 1070 | { | ||
| 1071 | disable_comm_shutdown(card); | ||
| 1072 | del_timer(&card->u.x.x25_timer); | ||
| 1073 | return; | ||
| 1074 | } | ||
| 1075 | |||
| 1076 | |||
| 1077 | /*============================================================ | ||
| 1078 | * Network Device Interface | ||
| 1079 | *===========================================================*/ | ||
| 1080 | |||
| 1081 | /*=================================================================== | ||
| 1082 | * Name: if_init(), Netowrk Interface Initialization | ||
| 1083 | * | ||
| 1084 | * Purpose: To initialize a network interface device structure. | ||
| 1085 | * | ||
| 1086 | * Rationale: During network interface startup, the if_init | ||
| 1087 | * is called by the kernel to initialize the | ||
| 1088 | * netowrk device structure. Thus a driver | ||
| 1089 | * can customze a network device. | ||
| 1090 | * | ||
| 1091 | * Description: Initialize the netowrk device call back | ||
| 1092 | * routines. This is where we tell the kernel | ||
| 1093 | * which function to use when it wants to send | ||
| 1094 | * via our interface. | ||
| 1095 | * Furthermore, we initialize the device flags, | ||
| 1096 | * MTU and physical address of the board. | ||
| 1097 | * | ||
| 1098 | * Called by: Kernel (/usr/src/linux/net/core/dev.c) | ||
| 1099 | * (dev->init()) | ||
| 1100 | * | ||
| 1101 | * Assumptions: None | ||
| 1102 | * | ||
| 1103 | * Warnings: None | ||
| 1104 | * | ||
| 1105 | * Return: 0 Ok : Void function. | ||
| 1106 | */ | ||
| 1107 | static int if_init(struct net_device* dev) | ||
| 1108 | { | ||
| 1109 | x25_channel_t* chan = dev->priv; | ||
| 1110 | sdla_t* card = chan->card; | ||
| 1111 | struct wan_device* wandev = &card->wandev; | ||
| 1112 | |||
| 1113 | /* Initialize device driver entry points */ | ||
| 1114 | dev->open = &if_open; | ||
| 1115 | dev->stop = &if_close; | ||
| 1116 | dev->hard_header = &if_header; | ||
| 1117 | dev->rebuild_header = &if_rebuild_hdr; | ||
| 1118 | dev->hard_start_xmit = &if_send; | ||
| 1119 | dev->get_stats = &if_stats; | ||
| 1120 | dev->tx_timeout = &if_tx_timeout; | ||
| 1121 | dev->watchdog_timeo = TX_TIMEOUT; | ||
| 1122 | |||
| 1123 | /* Initialize media-specific parameters */ | ||
| 1124 | dev->type = ARPHRD_PPP; /* ARP h/w type */ | ||
| 1125 | dev->flags |= IFF_POINTOPOINT; | ||
| 1126 | dev->flags |= IFF_NOARP; | ||
| 1127 | |||
| 1128 | if (chan->common.usedby == API){ | ||
| 1129 | dev->mtu = X25_CHAN_MTU+sizeof(x25api_hdr_t); | ||
| 1130 | }else{ | ||
| 1131 | dev->mtu = card->wandev.mtu; | ||
| 1132 | } | ||
| 1133 | |||
| 1134 | dev->hard_header_len = X25_HRDHDR_SZ; /* media header length */ | ||
| 1135 | dev->addr_len = 2; /* hardware address length */ | ||
| 1136 | |||
| 1137 | if (!chan->common.svc){ | ||
| 1138 | *(unsigned short*)dev->dev_addr = htons(chan->common.lcn); | ||
| 1139 | } | ||
| 1140 | |||
| 1141 | /* Initialize hardware parameters (just for reference) */ | ||
| 1142 | dev->irq = wandev->irq; | ||
| 1143 | dev->dma = wandev->dma; | ||
| 1144 | dev->base_addr = wandev->ioport; | ||
| 1145 | dev->mem_start = (unsigned long)wandev->maddr; | ||
| 1146 | dev->mem_end = wandev->maddr + wandev->msize - 1; | ||
| 1147 | |||
| 1148 | /* Set transmit buffer queue length */ | ||
| 1149 | dev->tx_queue_len = 100; | ||
| 1150 | SET_MODULE_OWNER(dev); | ||
| 1151 | |||
| 1152 | /* FIXME Why are we doing this */ | ||
| 1153 | set_chan_state(dev, WAN_DISCONNECTED); | ||
| 1154 | return 0; | ||
| 1155 | } | ||
| 1156 | |||
| 1157 | |||
| 1158 | /*=================================================================== | ||
| 1159 | * Name: if_open(), Open/Bring up the Netowrk Interface | ||
| 1160 | * | ||
| 1161 | * Purpose: To bring up a network interface. | ||
| 1162 | * | ||
| 1163 | * Rationale: | ||
| 1164 | * | ||
| 1165 | * Description: Open network interface. | ||
| 1166 | * o prevent module from unloading by incrementing use count | ||
| 1167 | * o if link is disconnected then initiate connection | ||
| 1168 | * | ||
| 1169 | * Called by: Kernel (/usr/src/linux/net/core/dev.c) | ||
| 1170 | * (dev->open()) | ||
| 1171 | * | ||
| 1172 | * Assumptions: None | ||
| 1173 | * | ||
| 1174 | * Warnings: None | ||
| 1175 | * | ||
| 1176 | * Return: 0 Ok | ||
| 1177 | * <0 Failure: Interface will not come up. | ||
| 1178 | */ | ||
| 1179 | |||
| 1180 | static int if_open(struct net_device* dev) | ||
| 1181 | { | ||
| 1182 | x25_channel_t* chan = dev->priv; | ||
| 1183 | sdla_t* card = chan->card; | ||
| 1184 | struct timeval tv; | ||
| 1185 | unsigned long smp_flags; | ||
| 1186 | |||
| 1187 | if (netif_running(dev)) | ||
| 1188 | return -EBUSY; | ||
| 1189 | |||
| 1190 | chan->tq_working = 0; | ||
| 1191 | |||
| 1192 | /* Initialize the workqueue */ | ||
| 1193 | INIT_WORK(&chan->common.wanpipe_work, (void *)x25api_bh, dev); | ||
| 1194 | |||
| 1195 | /* Allocate and initialize BH circular buffer */ | ||
| 1196 | /* Add 1 to MAX_BH_BUFF so we don't have test with (MAX_BH_BUFF-1) */ | ||
| 1197 | chan->bh_head = kmalloc((sizeof(bh_data_t)*(MAX_BH_BUFF+1)),GFP_ATOMIC); | ||
| 1198 | |||
| 1199 | if (chan->bh_head == NULL){ | ||
| 1200 | printk(KERN_INFO "%s: ERROR, failed to allocate memory ! BH_BUFFERS !\n", | ||
| 1201 | card->devname); | ||
| 1202 | |||
| 1203 | return -ENOBUFS; | ||
| 1204 | } | ||
| 1205 | memset(chan->bh_head,0,(sizeof(bh_data_t)*(MAX_BH_BUFF+1))); | ||
| 1206 | atomic_set(&chan->bh_buff_used, 0); | ||
| 1207 | |||
| 1208 | /* Increment the number of interfaces */ | ||
| 1209 | ++card->u.x.no_dev; | ||
| 1210 | |||
| 1211 | wanpipe_open(card); | ||
| 1212 | |||
| 1213 | /* LAPB protocol only uses one interface, thus | ||
| 1214 | * start the protocol after it comes up. */ | ||
| 1215 | if (card->u.x.LAPB_hdlc){ | ||
| 1216 | if (card->open_cnt == 1){ | ||
| 1217 | TX25Status* status = card->flags; | ||
| 1218 | S508_S514_lock(card, &smp_flags); | ||
| 1219 | x25_set_intr_mode(card, INTR_ON_TIMER); | ||
| 1220 | status->imask &= ~INTR_ON_TIMER; | ||
| 1221 | S508_S514_unlock(card, &smp_flags); | ||
| 1222 | } | ||
| 1223 | }else{ | ||
| 1224 | /* X25 can have multiple interfaces thus, start the | ||
| 1225 | * protocol once all interfaces are up */ | ||
| 1226 | |||
| 1227 | //FIXME: There is a bug here. If interface is | ||
| 1228 | //brought down and up, it will try to enable comm. | ||
| 1229 | if (card->open_cnt == card->u.x.num_of_ch){ | ||
| 1230 | |||
| 1231 | S508_S514_lock(card, &smp_flags); | ||
| 1232 | connect(card); | ||
| 1233 | S508_S514_unlock(card, &smp_flags); | ||
| 1234 | |||
| 1235 | mod_timer(&card->u.x.x25_timer, jiffies + HZ); | ||
| 1236 | } | ||
| 1237 | } | ||
| 1238 | /* Device is not up until the we are in connected state */ | ||
| 1239 | do_gettimeofday( &tv ); | ||
| 1240 | chan->router_start_time = tv.tv_sec; | ||
| 1241 | |||
| 1242 | netif_start_queue(dev); | ||
| 1243 | |||
| 1244 | return 0; | ||
| 1245 | } | ||
| 1246 | |||
| 1247 | /*=================================================================== | ||
| 1248 | * Name: if_close(), Close/Bring down the Netowrk Interface | ||
| 1249 | * | ||
| 1250 | * Purpose: To bring down a network interface. | ||
| 1251 | * | ||
| 1252 | * Rationale: | ||
| 1253 | * | ||
| 1254 | * Description: Close network interface. | ||
| 1255 | * o decrement use module use count | ||
| 1256 | * | ||
| 1257 | * Called by: Kernel (/usr/src/linux/net/core/dev.c) | ||
| 1258 | * (dev->close()) | ||
| 1259 | * ifconfig <name> down: will trigger the kernel | ||
| 1260 | * which will call this function. | ||
| 1261 | * | ||
| 1262 | * Assumptions: None | ||
| 1263 | * | ||
| 1264 | * Warnings: None | ||
| 1265 | * | ||
| 1266 | * Return: 0 Ok | ||
| 1267 | * <0 Failure: Interface will not exit properly. | ||
| 1268 | */ | ||
| 1269 | static int if_close(struct net_device* dev) | ||
| 1270 | { | ||
| 1271 | x25_channel_t* chan = dev->priv; | ||
| 1272 | sdla_t* card = chan->card; | ||
| 1273 | unsigned long smp_flags; | ||
| 1274 | |||
| 1275 | netif_stop_queue(dev); | ||
| 1276 | |||
| 1277 | if ((chan->common.state == WAN_CONNECTED) || | ||
| 1278 | (chan->common.state == WAN_CONNECTING)){ | ||
| 1279 | S508_S514_lock(card, &smp_flags); | ||
| 1280 | chan_disc(dev); | ||
| 1281 | S508_S514_unlock(card, &smp_flags); | ||
| 1282 | } | ||
| 1283 | |||
| 1284 | wanpipe_close(card); | ||
| 1285 | |||
| 1286 | S508_S514_lock(card, &smp_flags); | ||
| 1287 | if (chan->bh_head){ | ||
| 1288 | int i; | ||
| 1289 | struct sk_buff *skb; | ||
| 1290 | |||
| 1291 | for (i=0; i<(MAX_BH_BUFF+1); i++){ | ||
| 1292 | skb = ((bh_data_t *)&chan->bh_head[i])->skb; | ||
| 1293 | if (skb != NULL){ | ||
| 1294 | dev_kfree_skb_any(skb); | ||
| 1295 | } | ||
| 1296 | } | ||
| 1297 | kfree(chan->bh_head); | ||
| 1298 | chan->bh_head=NULL; | ||
| 1299 | } | ||
| 1300 | S508_S514_unlock(card, &smp_flags); | ||
| 1301 | |||
| 1302 | /* If this is the last close, disconnect physical link */ | ||
| 1303 | if (!card->open_cnt){ | ||
| 1304 | S508_S514_lock(card, &smp_flags); | ||
| 1305 | disconnect(card); | ||
| 1306 | x25_set_intr_mode(card, 0); | ||
| 1307 | S508_S514_unlock(card, &smp_flags); | ||
| 1308 | } | ||
| 1309 | |||
| 1310 | /* Decrement the number of interfaces */ | ||
| 1311 | --card->u.x.no_dev; | ||
| 1312 | return 0; | ||
| 1313 | } | ||
| 1314 | |||
| 1315 | /*====================================================================== | ||
| 1316 | * Build media header. | ||
| 1317 | * o encapsulate packet according to encapsulation type. | ||
| 1318 | * | ||
| 1319 | * The trick here is to put packet type (Ethertype) into 'protocol' | ||
| 1320 | * field of the socket buffer, so that we don't forget it. | ||
| 1321 | * If encapsulation fails, set skb->protocol to 0 and discard | ||
| 1322 | * packet later. | ||
| 1323 | * | ||
| 1324 | * Return: media header length. | ||
| 1325 | *======================================================================*/ | ||
| 1326 | |||
| 1327 | static int if_header(struct sk_buff* skb, struct net_device* dev, | ||
| 1328 | unsigned short type, void* daddr, void* saddr, | ||
| 1329 | unsigned len) | ||
| 1330 | { | ||
| 1331 | x25_channel_t* chan = dev->priv; | ||
| 1332 | int hdr_len = dev->hard_header_len; | ||
| 1333 | |||
| 1334 | skb->protocol = htons(type); | ||
| 1335 | if (!chan->protocol){ | ||
| 1336 | hdr_len = wanrouter_encapsulate(skb, dev, type); | ||
| 1337 | if (hdr_len < 0){ | ||
| 1338 | hdr_len = 0; | ||
| 1339 | skb->protocol = htons(0); | ||
| 1340 | } | ||
| 1341 | } | ||
| 1342 | return hdr_len; | ||
| 1343 | } | ||
| 1344 | |||
| 1345 | /*=============================================================== | ||
| 1346 | * Re-build media header. | ||
| 1347 | * | ||
| 1348 | * Return: 1 physical address resolved. | ||
| 1349 | * 0 physical address not resolved | ||
| 1350 | *==============================================================*/ | ||
| 1351 | |||
| 1352 | static int if_rebuild_hdr (struct sk_buff* skb) | ||
| 1353 | { | ||
| 1354 | struct net_device *dev = skb->dev; | ||
| 1355 | x25_channel_t* chan = dev->priv; | ||
| 1356 | sdla_t* card = chan->card; | ||
| 1357 | |||
| 1358 | printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", | ||
| 1359 | card->devname, dev->name); | ||
| 1360 | return 1; | ||
| 1361 | } | ||
| 1362 | |||
| 1363 | |||
| 1364 | /*============================================================================ | ||
| 1365 | * Handle transmit timeout event from netif watchdog | ||
| 1366 | */ | ||
| 1367 | static void if_tx_timeout(struct net_device *dev) | ||
| 1368 | { | ||
| 1369 | x25_channel_t* chan = dev->priv; | ||
| 1370 | sdla_t *card = chan->card; | ||
| 1371 | |||
| 1372 | /* If our device stays busy for at least 5 seconds then we will | ||
| 1373 | * kick start the device by making dev->tbusy = 0. We expect | ||
| 1374 | * that our device never stays busy more than 5 seconds. So this | ||
| 1375 | * is only used as a last resort. | ||
| 1376 | */ | ||
| 1377 | |||
| 1378 | ++chan->if_send_stat.if_send_tbusy_timeout; | ||
| 1379 | printk (KERN_INFO "%s: Transmit timed out on %s\n", | ||
| 1380 | card->devname, dev->name); | ||
| 1381 | netif_wake_queue (dev); | ||
| 1382 | } | ||
| 1383 | |||
| 1384 | |||
| 1385 | /*========================================================================= | ||
| 1386 | * Send a packet on a network interface. | ||
| 1387 | * o set tbusy flag (marks start of the transmission). | ||
| 1388 | * o check link state. If link is not up, then drop the packet. | ||
| 1389 | * o check channel status. If it's down then initiate a call. | ||
| 1390 | * o pass a packet to corresponding WAN device. | ||
| 1391 | * o free socket buffer | ||
| 1392 | * | ||
| 1393 | * Return: 0 complete (socket buffer must be freed) | ||
| 1394 | * non-0 packet may be re-transmitted (tbusy must be set) | ||
| 1395 | * | ||
| 1396 | * Notes: | ||
| 1397 | * 1. This routine is called either by the protocol stack or by the "net | ||
| 1398 | * bottom half" (with interrupts enabled). | ||
| 1399 | * 2. Setting tbusy flag will inhibit further transmit requests from the | ||
| 1400 | * protocol stack and can be used for flow control with protocol layer. | ||
| 1401 | * | ||
| 1402 | *========================================================================*/ | ||
| 1403 | |||
| 1404 | static int if_send(struct sk_buff* skb, struct net_device* dev) | ||
| 1405 | { | ||
| 1406 | x25_channel_t* chan = dev->priv; | ||
| 1407 | sdla_t* card = chan->card; | ||
| 1408 | TX25Status* status = card->flags; | ||
| 1409 | int udp_type; | ||
| 1410 | unsigned long smp_flags=0; | ||
| 1411 | |||
| 1412 | ++chan->if_send_stat.if_send_entry; | ||
| 1413 | |||
| 1414 | netif_stop_queue(dev); | ||
| 1415 | |||
| 1416 | /* No need to check frame length, since socket code | ||
| 1417 | * will perform the check for us */ | ||
| 1418 | |||
| 1419 | chan->tick_counter = jiffies; | ||
| 1420 | |||
| 1421 | /* Critical region starts here */ | ||
| 1422 | S508_S514_lock(card, &smp_flags); | ||
| 1423 | |||
| 1424 | if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)){ | ||
| 1425 | printk(KERN_INFO "Hit critical in if_send()! %lx\n",card->wandev.critical); | ||
| 1426 | goto if_send_crit_exit; | ||
| 1427 | } | ||
| 1428 | |||
| 1429 | udp_type = udp_pkt_type(skb, card); | ||
| 1430 | |||
| 1431 | if(udp_type != UDP_INVALID_TYPE) { | ||
| 1432 | |||
| 1433 | if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, dev, skb, | ||
| 1434 | chan->common.lcn)) { | ||
| 1435 | |||
| 1436 | status->imask |= INTR_ON_TIMER; | ||
| 1437 | if (udp_type == UDP_XPIPE_TYPE){ | ||
| 1438 | chan->if_send_stat.if_send_PIPE_request++; | ||
| 1439 | } | ||
| 1440 | } | ||
| 1441 | netif_start_queue(dev); | ||
| 1442 | clear_bit(SEND_CRIT,(void*)&card->wandev.critical); | ||
| 1443 | S508_S514_unlock(card, &smp_flags); | ||
| 1444 | return 0; | ||
| 1445 | } | ||
| 1446 | |||
| 1447 | if (chan->transmit_length){ | ||
| 1448 | //FIXME: This check doesn't make sense any more | ||
| 1449 | if (chan->common.state != WAN_CONNECTED){ | ||
| 1450 | chan->transmit_length=0; | ||
| 1451 | atomic_set(&chan->common.driver_busy,0); | ||
| 1452 | }else{ | ||
| 1453 | netif_stop_queue(dev); | ||
| 1454 | ++card->u.x.tx_interrupts_pending; | ||
| 1455 | status->imask |= INTR_ON_TX_FRAME; | ||
| 1456 | clear_bit(SEND_CRIT,(void*)&card->wandev.critical); | ||
| 1457 | S508_S514_unlock(card, &smp_flags); | ||
| 1458 | return 1; | ||
| 1459 | } | ||
| 1460 | } | ||
| 1461 | |||
| 1462 | if (card->wandev.state != WAN_CONNECTED){ | ||
| 1463 | ++chan->ifstats.tx_dropped; | ||
| 1464 | ++card->wandev.stats.tx_dropped; | ||
| 1465 | ++chan->if_send_stat.if_send_wan_disconnected; | ||
| 1466 | |||
| 1467 | }else if ( chan->protocol && (chan->protocol != skb->protocol)){ | ||
| 1468 | printk(KERN_INFO | ||
| 1469 | "%s: unsupported Ethertype 0x%04X on interface %s!\n", | ||
| 1470 | chan->name, htons(skb->protocol), dev->name); | ||
| 1471 | |||
| 1472 | printk(KERN_INFO "PROTO %Xn", htons(chan->protocol)); | ||
| 1473 | ++chan->ifstats.tx_errors; | ||
| 1474 | ++chan->ifstats.tx_dropped; | ||
| 1475 | ++card->wandev.stats.tx_dropped; | ||
| 1476 | ++chan->if_send_stat.if_send_protocol_error; | ||
| 1477 | |||
| 1478 | }else switch (chan->common.state){ | ||
| 1479 | |||
| 1480 | case WAN_DISCONNECTED: | ||
| 1481 | /* Try to establish connection. If succeded, then start | ||
| 1482 | * transmission, else drop a packet. | ||
| 1483 | */ | ||
| 1484 | if (chan->common.usedby == API){ | ||
| 1485 | ++chan->ifstats.tx_dropped; | ||
| 1486 | ++card->wandev.stats.tx_dropped; | ||
| 1487 | break; | ||
| 1488 | }else{ | ||
| 1489 | if (chan_connect(dev) != 0){ | ||
| 1490 | ++chan->ifstats.tx_dropped; | ||
| 1491 | ++card->wandev.stats.tx_dropped; | ||
| 1492 | break; | ||
| 1493 | } | ||
| 1494 | } | ||
| 1495 | /* fall through */ | ||
| 1496 | |||
| 1497 | case WAN_CONNECTED: | ||
| 1498 | if( skb->protocol == htons(ETH_P_IPX)) { | ||
| 1499 | if(chan->enable_IPX) { | ||
| 1500 | switch_net_numbers( skb->data, | ||
| 1501 | chan->network_number, 0); | ||
| 1502 | } else { | ||
| 1503 | ++card->wandev.stats.tx_dropped; | ||
| 1504 | ++chan->ifstats.tx_dropped; | ||
| 1505 | ++chan->if_send_stat.if_send_protocol_error; | ||
| 1506 | goto if_send_crit_exit; | ||
| 1507 | } | ||
| 1508 | } | ||
| 1509 | /* We never drop here, if cannot send than, copy | ||
| 1510 | * a packet into a transmit buffer | ||
| 1511 | */ | ||
| 1512 | chan_send(dev, skb->data, skb->len, 0); | ||
| 1513 | break; | ||
| 1514 | |||
| 1515 | default: | ||
| 1516 | ++chan->ifstats.tx_dropped; | ||
| 1517 | ++card->wandev.stats.tx_dropped; | ||
| 1518 | break; | ||
| 1519 | } | ||
| 1520 | |||
| 1521 | |||
| 1522 | if_send_crit_exit: | ||
| 1523 | |||
| 1524 | dev_kfree_skb_any(skb); | ||
| 1525 | |||
| 1526 | netif_start_queue(dev); | ||
| 1527 | clear_bit(SEND_CRIT,(void*)&card->wandev.critical); | ||
| 1528 | S508_S514_unlock(card, &smp_flags); | ||
| 1529 | return 0; | ||
| 1530 | } | ||
| 1531 | |||
| 1532 | /*============================================================================ | ||
| 1533 | * Setup so that a frame can be transmitted on the occurrence of a transmit | ||
| 1534 | * interrupt. | ||
| 1535 | *===========================================================================*/ | ||
| 1536 | |||
| 1537 | static void setup_for_delayed_transmit(struct net_device* dev, void* buf, | ||
| 1538 | unsigned len) | ||
| 1539 | { | ||
| 1540 | x25_channel_t* chan = dev->priv; | ||
| 1541 | sdla_t* card = chan->card; | ||
| 1542 | TX25Status* status = card->flags; | ||
| 1543 | |||
| 1544 | ++chan->if_send_stat.if_send_adptr_bfrs_full; | ||
| 1545 | |||
| 1546 | if(chan->transmit_length) { | ||
| 1547 | printk(KERN_INFO "%s: Error, transmit length set in delayed transmit!\n", | ||
| 1548 | card->devname); | ||
| 1549 | return; | ||
| 1550 | } | ||
| 1551 | |||
| 1552 | if (chan->common.usedby == API){ | ||
| 1553 | if (len > X25_CHAN_MTU+sizeof(x25api_hdr_t)) { | ||
| 1554 | ++chan->ifstats.tx_dropped; | ||
| 1555 | ++card->wandev.stats.tx_dropped; | ||
| 1556 | printk(KERN_INFO "%s: Length is too big for delayed transmit\n", | ||
| 1557 | card->devname); | ||
| 1558 | return; | ||
| 1559 | } | ||
| 1560 | }else{ | ||
| 1561 | if (len > X25_MAX_DATA) { | ||
| 1562 | ++chan->ifstats.tx_dropped; | ||
| 1563 | ++card->wandev.stats.tx_dropped; | ||
| 1564 | printk(KERN_INFO "%s: Length is too big for delayed transmit\n", | ||
| 1565 | card->devname); | ||
| 1566 | return; | ||
| 1567 | } | ||
| 1568 | } | ||
| 1569 | |||
| 1570 | chan->transmit_length = len; | ||
| 1571 | atomic_set(&chan->common.driver_busy,1); | ||
| 1572 | memcpy(chan->transmit_buffer, buf, len); | ||
| 1573 | |||
| 1574 | ++chan->if_send_stat.if_send_tx_int_enabled; | ||
| 1575 | |||
| 1576 | /* Enable Transmit Interrupt */ | ||
| 1577 | ++card->u.x.tx_interrupts_pending; | ||
| 1578 | status->imask |= INTR_ON_TX_FRAME; | ||
| 1579 | } | ||
| 1580 | |||
| 1581 | |||
| 1582 | /*=============================================================== | ||
| 1583 | * net_device_stats | ||
| 1584 | * | ||
| 1585 | * Get ethernet-style interface statistics. | ||
| 1586 | * Return a pointer to struct enet_statistics. | ||
| 1587 | * | ||
| 1588 | *==============================================================*/ | ||
| 1589 | static struct net_device_stats *if_stats(struct net_device* dev) | ||
| 1590 | { | ||
| 1591 | x25_channel_t *chan = dev->priv; | ||
| 1592 | |||
| 1593 | if(chan == NULL) | ||
| 1594 | return NULL; | ||
| 1595 | |||
| 1596 | return &chan->ifstats; | ||
| 1597 | } | ||
| 1598 | |||
| 1599 | |||
| 1600 | /* | ||
| 1601 | * Interrupt Handlers | ||
| 1602 | */ | ||
| 1603 | |||
| 1604 | /* | ||
| 1605 | * X.25 Interrupt Service Routine. | ||
| 1606 | */ | ||
| 1607 | |||
| 1608 | static void wpx_isr (sdla_t* card) | ||
| 1609 | { | ||
| 1610 | TX25Status* status = card->flags; | ||
| 1611 | |||
| 1612 | card->in_isr = 1; | ||
| 1613 | ++card->statistics.isr_entry; | ||
| 1614 | |||
| 1615 | if (test_bit(PERI_CRIT,(void*)&card->wandev.critical)){ | ||
| 1616 | card->in_isr=0; | ||
| 1617 | status->iflags = 0; | ||
| 1618 | return; | ||
| 1619 | } | ||
| 1620 | |||
| 1621 | if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)){ | ||
| 1622 | |||
| 1623 | printk(KERN_INFO "%s: wpx_isr: wandev.critical set to 0x%02lx, int type = 0x%02x\n", | ||
| 1624 | card->devname, card->wandev.critical, status->iflags); | ||
| 1625 | card->in_isr = 0; | ||
| 1626 | status->iflags = 0; | ||
| 1627 | return; | ||
| 1628 | } | ||
| 1629 | |||
| 1630 | /* For all interrupts set the critical flag to CRITICAL_RX_INTR. | ||
| 1631 | * If the if_send routine is called with this flag set it will set | ||
| 1632 | * the enable transmit flag to 1. (for a delayed interrupt) | ||
| 1633 | */ | ||
| 1634 | switch (status->iflags){ | ||
| 1635 | |||
| 1636 | case RX_INTR_PENDING: /* receive interrupt */ | ||
| 1637 | rx_intr(card); | ||
| 1638 | break; | ||
| 1639 | |||
| 1640 | case TX_INTR_PENDING: /* transmit interrupt */ | ||
| 1641 | tx_intr(card); | ||
| 1642 | break; | ||
| 1643 | |||
| 1644 | case MODEM_INTR_PENDING: /* modem status interrupt */ | ||
| 1645 | status_intr(card); | ||
| 1646 | break; | ||
| 1647 | |||
| 1648 | case X25_ASY_TRANS_INTR_PENDING: /* network event interrupt */ | ||
| 1649 | event_intr(card); | ||
| 1650 | break; | ||
| 1651 | |||
| 1652 | case TIMER_INTR_PENDING: | ||
| 1653 | timer_intr(card); | ||
| 1654 | break; | ||
| 1655 | |||
| 1656 | default: /* unwanted interrupt */ | ||
| 1657 | spur_intr(card); | ||
| 1658 | } | ||
| 1659 | |||
| 1660 | card->in_isr = 0; | ||
| 1661 | status->iflags = 0; /* clear interrupt condition */ | ||
| 1662 | } | ||
| 1663 | |||
| 1664 | /* | ||
| 1665 | * Receive interrupt handler. | ||
| 1666 | * This routine handles fragmented IP packets using M-bit according to the | ||
| 1667 | * RFC1356. | ||
| 1668 | * o map ligical channel number to network interface. | ||
| 1669 | * o allocate socket buffer or append received packet to the existing one. | ||
| 1670 | * o if M-bit is reset (i.e. it's the last packet in a sequence) then | ||
| 1671 | * decapsulate packet and pass socket buffer to the protocol stack. | ||
| 1672 | * | ||
| 1673 | * Notes: | ||
| 1674 | * 1. When allocating a socket buffer, if M-bit is set then more data is | ||
| 1675 | * coming and we have to allocate buffer for the maximum IP packet size | ||
| 1676 | * expected on this channel. | ||
| 1677 | * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no | ||
| 1678 | * socket buffers available) the whole packet sequence must be discarded. | ||
| 1679 | */ | ||
| 1680 | |||
| 1681 | static void rx_intr (sdla_t* card) | ||
| 1682 | { | ||
| 1683 | TX25Mbox* rxmb = card->rxmb; | ||
| 1684 | unsigned lcn = rxmb->cmd.lcn; | ||
| 1685 | struct net_device* dev = find_channel(card,lcn); | ||
| 1686 | x25_channel_t* chan; | ||
| 1687 | struct sk_buff* skb=NULL; | ||
| 1688 | |||
| 1689 | if (dev == NULL){ | ||
| 1690 | /* Invalid channel, discard packet */ | ||
| 1691 | printk(KERN_INFO "%s: receiving on orphaned LCN %d!\n", | ||
| 1692 | card->devname, lcn); | ||
| 1693 | return; | ||
| 1694 | } | ||
| 1695 | |||
| 1696 | chan = dev->priv; | ||
| 1697 | chan->i_timeout_sofar = jiffies; | ||
| 1698 | |||
| 1699 | |||
| 1700 | /* Copy the data from the board, into an | ||
| 1701 | * skb buffer | ||
| 1702 | */ | ||
| 1703 | if (wanpipe_pull_data_in_skb(card,dev,&skb)){ | ||
| 1704 | ++chan->ifstats.rx_dropped; | ||
| 1705 | ++card->wandev.stats.rx_dropped; | ||
| 1706 | ++chan->rx_intr_stat.rx_intr_no_socket; | ||
| 1707 | ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; | ||
| 1708 | return; | ||
| 1709 | } | ||
| 1710 | |||
| 1711 | dev->last_rx = jiffies; /* timestamp */ | ||
| 1712 | |||
| 1713 | |||
| 1714 | /* ------------ API ----------------*/ | ||
| 1715 | |||
| 1716 | if (chan->common.usedby == API){ | ||
| 1717 | |||
| 1718 | if (bh_enqueue(dev, skb)){ | ||
| 1719 | ++chan->ifstats.rx_dropped; | ||
| 1720 | ++card->wandev.stats.rx_dropped; | ||
| 1721 | ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; | ||
| 1722 | dev_kfree_skb_any(skb); | ||
| 1723 | return; | ||
| 1724 | } | ||
| 1725 | |||
| 1726 | ++chan->ifstats.rx_packets; | ||
| 1727 | chan->ifstats.rx_bytes += skb->len; | ||
| 1728 | |||
| 1729 | |||
| 1730 | chan->rx_skb = NULL; | ||
| 1731 | if (!test_and_set_bit(0, &chan->tq_working)){ | ||
| 1732 | wanpipe_queue_work(&chan->common.wanpipe_work); | ||
| 1733 | } | ||
| 1734 | return; | ||
| 1735 | } | ||
| 1736 | |||
| 1737 | |||
| 1738 | /* ------------- WANPIPE -------------------*/ | ||
| 1739 | |||
| 1740 | /* set rx_skb to NULL so we won't access it later when kernel already owns it */ | ||
| 1741 | chan->rx_skb=NULL; | ||
| 1742 | |||
| 1743 | /* Decapsulate packet, if necessary */ | ||
| 1744 | if (!skb->protocol && !wanrouter_type_trans(skb, dev)){ | ||
| 1745 | /* can't decapsulate packet */ | ||
| 1746 | dev_kfree_skb_any(skb); | ||
| 1747 | ++chan->ifstats.rx_errors; | ||
| 1748 | ++chan->ifstats.rx_dropped; | ||
| 1749 | ++card->wandev.stats.rx_dropped; | ||
| 1750 | ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; | ||
| 1751 | |||
| 1752 | }else{ | ||
| 1753 | if( handle_IPXWAN(skb->data, chan->name, | ||
| 1754 | chan->enable_IPX, chan->network_number, | ||
| 1755 | skb->protocol)){ | ||
| 1756 | |||
| 1757 | if( chan->enable_IPX ){ | ||
| 1758 | if(chan_send(dev, skb->data, skb->len,0)){ | ||
| 1759 | chan->tx_skb = skb; | ||
| 1760 | }else{ | ||
| 1761 | dev_kfree_skb_any(skb); | ||
| 1762 | ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; | ||
| 1763 | } | ||
| 1764 | }else{ | ||
| 1765 | /* increment IPX packet dropped statistic */ | ||
| 1766 | ++chan->ifstats.rx_dropped; | ||
| 1767 | ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; | ||
| 1768 | } | ||
| 1769 | }else{ | ||
| 1770 | skb->mac.raw = skb->data; | ||
| 1771 | chan->ifstats.rx_bytes += skb->len; | ||
| 1772 | ++chan->ifstats.rx_packets; | ||
| 1773 | ++chan->rx_intr_stat.rx_intr_bfr_passed_to_stack; | ||
| 1774 | netif_rx(skb); | ||
| 1775 | } | ||
| 1776 | } | ||
| 1777 | |||
| 1778 | return; | ||
| 1779 | } | ||
| 1780 | |||
| 1781 | |||
| 1782 | static int wanpipe_pull_data_in_skb(sdla_t *card, struct net_device *dev, | ||
| 1783 | struct sk_buff **skb) | ||
| 1784 | { | ||
| 1785 | void *bufptr; | ||
| 1786 | TX25Mbox* rxmb = card->rxmb; | ||
| 1787 | unsigned len = rxmb->cmd.length; /* packet length */ | ||
| 1788 | unsigned qdm = rxmb->cmd.qdm; /* Q,D and M bits */ | ||
| 1789 | x25_channel_t *chan = dev->priv; | ||
| 1790 | struct sk_buff *new_skb = *skb; | ||
| 1791 | |||
| 1792 | if (chan->common.usedby == WANPIPE){ | ||
| 1793 | if (chan->drop_sequence){ | ||
| 1794 | if (!(qdm & 0x01)){ | ||
| 1795 | chan->drop_sequence = 0; | ||
| 1796 | } | ||
| 1797 | return 1; | ||
| 1798 | } | ||
| 1799 | new_skb = chan->rx_skb; | ||
| 1800 | }else{ | ||
| 1801 | /* Add on the API header to the received | ||
| 1802 | * data | ||
| 1803 | */ | ||
| 1804 | len += sizeof(x25api_hdr_t); | ||
| 1805 | } | ||
| 1806 | |||
| 1807 | if (new_skb == NULL){ | ||
| 1808 | int bufsize; | ||
| 1809 | |||
| 1810 | if (chan->common.usedby == WANPIPE){ | ||
| 1811 | bufsize = (qdm & 0x01) ? dev->mtu : len; | ||
| 1812 | }else{ | ||
| 1813 | bufsize = len; | ||
| 1814 | } | ||
| 1815 | |||
| 1816 | /* Allocate new socket buffer */ | ||
| 1817 | new_skb = dev_alloc_skb(bufsize + dev->hard_header_len); | ||
| 1818 | if (new_skb == NULL){ | ||
| 1819 | printk(KERN_INFO "%s: no socket buffers available!\n", | ||
| 1820 | card->devname); | ||
| 1821 | chan->drop_sequence = 1; /* set flag */ | ||
| 1822 | ++chan->ifstats.rx_dropped; | ||
| 1823 | return 1; | ||
| 1824 | } | ||
| 1825 | } | ||
| 1826 | |||
| 1827 | if (skb_tailroom(new_skb) < len){ | ||
| 1828 | /* No room for the packet. Call off the whole thing! */ | ||
| 1829 | dev_kfree_skb_any(new_skb); | ||
| 1830 | if (chan->common.usedby == WANPIPE){ | ||
| 1831 | chan->rx_skb = NULL; | ||
| 1832 | if (qdm & 0x01){ | ||
| 1833 | chan->drop_sequence = 1; | ||
| 1834 | } | ||
| 1835 | } | ||
| 1836 | |||
| 1837 | printk(KERN_INFO "%s: unexpectedly long packet sequence " | ||
| 1838 | "on interface %s!\n", card->devname, dev->name); | ||
| 1839 | ++chan->ifstats.rx_length_errors; | ||
| 1840 | return 1; | ||
| 1841 | } | ||
| 1842 | |||
| 1843 | bufptr = skb_put(new_skb,len); | ||
| 1844 | |||
| 1845 | |||
| 1846 | if (chan->common.usedby == API){ | ||
| 1847 | /* Fill in the x25api header | ||
| 1848 | */ | ||
| 1849 | x25api_t * api_data = (x25api_t*)bufptr; | ||
| 1850 | api_data->hdr.qdm = rxmb->cmd.qdm; | ||
| 1851 | api_data->hdr.cause = rxmb->cmd.cause; | ||
| 1852 | api_data->hdr.diagn = rxmb->cmd.diagn; | ||
| 1853 | api_data->hdr.length = rxmb->cmd.length; | ||
| 1854 | memcpy(api_data->data, rxmb->data, rxmb->cmd.length); | ||
| 1855 | }else{ | ||
| 1856 | memcpy(bufptr, rxmb->data, len); | ||
| 1857 | } | ||
| 1858 | |||
| 1859 | new_skb->dev = dev; | ||
| 1860 | |||
| 1861 | if (chan->common.usedby == API){ | ||
| 1862 | new_skb->mac.raw = new_skb->data; | ||
| 1863 | new_skb->protocol = htons(X25_PROT); | ||
| 1864 | new_skb->pkt_type = WAN_PACKET_DATA; | ||
| 1865 | }else{ | ||
| 1866 | new_skb->protocol = chan->protocol; | ||
| 1867 | chan->rx_skb = new_skb; | ||
| 1868 | } | ||
| 1869 | |||
| 1870 | /* If qdm bit is set, more data is coming | ||
| 1871 | * thus, exit and wait for more data before | ||
| 1872 | * sending the packet up. (Used by router only) | ||
| 1873 | */ | ||
| 1874 | if ((qdm & 0x01) && (chan->common.usedby == WANPIPE)) | ||
| 1875 | return 1; | ||
| 1876 | |||
| 1877 | *skb = new_skb; | ||
| 1878 | |||
| 1879 | return 0; | ||
| 1880 | } | ||
| 1881 | |||
| 1882 | /*=============================================================== | ||
| 1883 | * tx_intr | ||
| 1884 | * | ||
| 1885 | * Transmit interrupt handler. | ||
| 1886 | * For each dev, check that there is something to send. | ||
| 1887 | * If data available, transmit. | ||
| 1888 | * | ||
| 1889 | *===============================================================*/ | ||
| 1890 | |||
| 1891 | static void tx_intr (sdla_t* card) | ||
| 1892 | { | ||
| 1893 | struct net_device *dev; | ||
| 1894 | TX25Status* status = card->flags; | ||
| 1895 | unsigned char more_to_tx=0; | ||
| 1896 | x25_channel_t *chan=NULL; | ||
| 1897 | int i=0; | ||
| 1898 | |||
| 1899 | if (card->u.x.tx_dev == NULL){ | ||
| 1900 | card->u.x.tx_dev = card->wandev.dev; | ||
| 1901 | } | ||
| 1902 | |||
| 1903 | dev = card->u.x.tx_dev; | ||
| 1904 | |||
| 1905 | for (;;){ | ||
| 1906 | |||
| 1907 | chan = dev->priv; | ||
| 1908 | if (chan->transmit_length){ | ||
| 1909 | /* Device was set to transmit, check if the TX | ||
| 1910 | * buffers are available | ||
| 1911 | */ | ||
| 1912 | if (chan->common.state != WAN_CONNECTED){ | ||
| 1913 | chan->transmit_length = 0; | ||
| 1914 | atomic_set(&chan->common.driver_busy,0); | ||
| 1915 | chan->tx_offset=0; | ||
| 1916 | if (netif_queue_stopped(dev)){ | ||
| 1917 | if (chan->common.usedby == API){ | ||
| 1918 | netif_start_queue(dev); | ||
| 1919 | wakeup_sk_bh(dev); | ||
| 1920 | }else{ | ||
| 1921 | netif_wake_queue(dev); | ||
| 1922 | } | ||
| 1923 | } | ||
| 1924 | dev = move_dev_to_next(card,dev); | ||
| 1925 | break; | ||
| 1926 | } | ||
| 1927 | |||
| 1928 | if ((status->cflags[chan->ch_idx] & 0x40 || card->u.x.LAPB_hdlc) && | ||
| 1929 | (*card->u.x.hdlc_buf_status & 0x40) ){ | ||
| 1930 | /* Tx buffer available, we can send */ | ||
| 1931 | |||
| 1932 | if (tx_intr_send(card, dev)){ | ||
| 1933 | more_to_tx=1; | ||
| 1934 | } | ||
| 1935 | |||
| 1936 | /* If more than one interface present, move the | ||
| 1937 | * device pointer to the next interface, so on the | ||
| 1938 | * next TX interrupt we will try sending from it. | ||
| 1939 | */ | ||
| 1940 | dev = move_dev_to_next(card,dev); | ||
| 1941 | break; | ||
| 1942 | }else{ | ||
| 1943 | /* Tx buffers not available, but device set | ||
| 1944 | * the TX interrupt. Set more_to_tx and try | ||
| 1945 | * to transmit for other devices. | ||
| 1946 | */ | ||
| 1947 | more_to_tx=1; | ||
| 1948 | dev = move_dev_to_next(card,dev); | ||
| 1949 | } | ||
| 1950 | |||
| 1951 | }else{ | ||
| 1952 | /* This device was not set to transmit, | ||
| 1953 | * go to next | ||
| 1954 | */ | ||
| 1955 | dev = move_dev_to_next(card,dev); | ||
| 1956 | } | ||
| 1957 | |||
| 1958 | if (++i == card->u.x.no_dev){ | ||
| 1959 | if (!more_to_tx){ | ||
| 1960 | DBG_PRINTK(KERN_INFO "%s: Nothing to Send in TX INTR\n", | ||
| 1961 | card->devname); | ||
| 1962 | } | ||
| 1963 | break; | ||
| 1964 | } | ||
| 1965 | |||
| 1966 | } //End of FOR | ||
| 1967 | |||
| 1968 | card->u.x.tx_dev = dev; | ||
| 1969 | |||
| 1970 | if (!more_to_tx){ | ||
| 1971 | /* if any other interfaces have transmit interrupts pending, */ | ||
| 1972 | /* do not disable the global transmit interrupt */ | ||
| 1973 | if (!(--card->u.x.tx_interrupts_pending)){ | ||
| 1974 | status->imask &= ~INTR_ON_TX_FRAME; | ||
| 1975 | } | ||
| 1976 | } | ||
| 1977 | return; | ||
| 1978 | } | ||
| 1979 | |||
| 1980 | /*=============================================================== | ||
| 1981 | * move_dev_to_next | ||
| 1982 | * | ||
| 1983 | * | ||
| 1984 | *===============================================================*/ | ||
| 1985 | |||
| 1986 | |||
| 1987 | struct net_device *move_dev_to_next(sdla_t *card, struct net_device *dev) | ||
| 1988 | { | ||
| 1989 | if (card->u.x.no_dev != 1){ | ||
| 1990 | if (!*((struct net_device **)dev->priv)) | ||
| 1991 | return card->wandev.dev; | ||
| 1992 | else | ||
| 1993 | return *((struct net_device **)dev->priv); | ||
| 1994 | } | ||
| 1995 | return dev; | ||
| 1996 | } | ||
| 1997 | |||
| 1998 | /*=============================================================== | ||
| 1999 | * tx_intr_send | ||
| 2000 | * | ||
| 2001 | * | ||
| 2002 | *===============================================================*/ | ||
| 2003 | |||
| 2004 | static int tx_intr_send(sdla_t *card, struct net_device *dev) | ||
| 2005 | { | ||
| 2006 | x25_channel_t* chan = dev->priv; | ||
| 2007 | |||
| 2008 | if (chan_send (dev,chan->transmit_buffer,chan->transmit_length,1)){ | ||
| 2009 | |||
| 2010 | /* Packet was split up due to its size, do not disable | ||
| 2011 | * tx_intr | ||
| 2012 | */ | ||
| 2013 | return 1; | ||
| 2014 | } | ||
| 2015 | |||
| 2016 | chan->transmit_length=0; | ||
| 2017 | atomic_set(&chan->common.driver_busy,0); | ||
| 2018 | chan->tx_offset=0; | ||
| 2019 | |||
| 2020 | /* If we are in API mode, wakeup the | ||
| 2021 | * sock BH handler, not the NET_BH */ | ||
| 2022 | if (netif_queue_stopped(dev)){ | ||
| 2023 | if (chan->common.usedby == API){ | ||
| 2024 | netif_start_queue(dev); | ||
| 2025 | wakeup_sk_bh(dev); | ||
| 2026 | }else{ | ||
| 2027 | netif_wake_queue(dev); | ||
| 2028 | } | ||
| 2029 | } | ||
| 2030 | return 0; | ||
| 2031 | } | ||
| 2032 | |||
| 2033 | |||
| 2034 | /*=============================================================== | ||
| 2035 | * timer_intr | ||
| 2036 | * | ||
| 2037 | * Timer interrupt handler. | ||
| 2038 | * Check who called the timer interrupt and perform | ||
| 2039 | * action accordingly. | ||
| 2040 | * | ||
| 2041 | *===============================================================*/ | ||
| 2042 | |||
| 2043 | static void timer_intr (sdla_t *card) | ||
| 2044 | { | ||
| 2045 | TX25Status* status = card->flags; | ||
| 2046 | |||
| 2047 | if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC){ | ||
| 2048 | |||
| 2049 | if (timer_intr_cmd_exec(card) == 0){ | ||
| 2050 | card->u.x.timer_int_enabled &= | ||
| 2051 | ~TMR_INT_ENABLED_CMD_EXEC; | ||
| 2052 | } | ||
| 2053 | |||
| 2054 | }else if(card->u.x.timer_int_enabled & TMR_INT_ENABLED_UDP_PKT) { | ||
| 2055 | |||
| 2056 | if ((*card->u.x.hdlc_buf_status & 0x40) && | ||
| 2057 | card->u.x.udp_type == UDP_XPIPE_TYPE){ | ||
| 2058 | |||
| 2059 | if(process_udp_mgmt_pkt(card)) { | ||
| 2060 | card->u.x.timer_int_enabled &= | ||
| 2061 | ~TMR_INT_ENABLED_UDP_PKT; | ||
| 2062 | } | ||
| 2063 | } | ||
| 2064 | |||
| 2065 | }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_ACTIVE) { | ||
| 2066 | |||
| 2067 | struct net_device *dev = card->u.x.poll_device; | ||
| 2068 | x25_channel_t *chan = NULL; | ||
| 2069 | |||
| 2070 | if (!dev){ | ||
| 2071 | card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_ACTIVE; | ||
| 2072 | return; | ||
| 2073 | } | ||
| 2074 | chan = dev->priv; | ||
| 2075 | |||
| 2076 | printk(KERN_INFO | ||
| 2077 | "%s: Closing down Idle link %s on LCN %d\n", | ||
| 2078 | card->devname,chan->name,chan->common.lcn); | ||
| 2079 | chan->i_timeout_sofar = jiffies; | ||
| 2080 | chan_disc(dev); | ||
| 2081 | card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_ACTIVE; | ||
| 2082 | card->u.x.poll_device=NULL; | ||
| 2083 | |||
| 2084 | }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_CONNECT_ON) { | ||
| 2085 | |||
| 2086 | wanpipe_set_state(card, WAN_CONNECTED); | ||
| 2087 | if (card->u.x.LAPB_hdlc){ | ||
| 2088 | struct net_device *dev = card->wandev.dev; | ||
| 2089 | set_chan_state(dev,WAN_CONNECTED); | ||
| 2090 | send_delayed_cmd_result(card,dev,card->mbox); | ||
| 2091 | } | ||
| 2092 | |||
| 2093 | /* 0x8F enable all interrupts */ | ||
| 2094 | x25_set_intr_mode(card, INTR_ON_RX_FRAME| | ||
| 2095 | INTR_ON_TX_FRAME| | ||
| 2096 | INTR_ON_MODEM_STATUS_CHANGE| | ||
| 2097 | //INTR_ON_COMMAND_COMPLETE| | ||
| 2098 | X25_ASY_TRANS_INTR_PENDING | | ||
| 2099 | INTR_ON_TIMER | | ||
| 2100 | DIRECT_RX_INTR_USAGE | ||
| 2101 | ); | ||
| 2102 | |||
| 2103 | status->imask &= ~INTR_ON_TX_FRAME; /* mask Tx interrupts */ | ||
| 2104 | card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_CONNECT_ON; | ||
| 2105 | |||
| 2106 | }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_CONNECT_OFF) { | ||
| 2107 | |||
| 2108 | //printk(KERN_INFO "Poll connect, Turning OFF\n"); | ||
| 2109 | disconnect(card); | ||
| 2110 | card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_CONNECT_OFF; | ||
| 2111 | |||
| 2112 | }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_DISCONNECT) { | ||
| 2113 | |||
| 2114 | //printk(KERN_INFO "POll disconnect, trying to connect\n"); | ||
| 2115 | connect(card); | ||
| 2116 | card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_DISCONNECT; | ||
| 2117 | |||
| 2118 | }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_UPDATE){ | ||
| 2119 | |||
| 2120 | if (*card->u.x.hdlc_buf_status & 0x40){ | ||
| 2121 | x25_get_err_stats(card); | ||
| 2122 | x25_get_stats(card); | ||
| 2123 | card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; | ||
| 2124 | } | ||
| 2125 | } | ||
| 2126 | |||
| 2127 | if(!card->u.x.timer_int_enabled){ | ||
| 2128 | //printk(KERN_INFO "Turning Timer Off \n"); | ||
| 2129 | status->imask &= ~INTR_ON_TIMER; | ||
| 2130 | } | ||
| 2131 | } | ||
| 2132 | |||
| 2133 | /*==================================================================== | ||
| 2134 | * Modem status interrupt handler. | ||
| 2135 | *===================================================================*/ | ||
| 2136 | static void status_intr (sdla_t* card) | ||
| 2137 | { | ||
| 2138 | |||
| 2139 | /* Added to avoid Modem status message flooding */ | ||
| 2140 | static TX25ModemStatus last_stat; | ||
| 2141 | |||
| 2142 | TX25Mbox* mbox = card->mbox; | ||
| 2143 | TX25ModemStatus *modem_status; | ||
| 2144 | struct net_device *dev; | ||
| 2145 | x25_channel_t *chan; | ||
| 2146 | int err; | ||
| 2147 | |||
| 2148 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
| 2149 | mbox->cmd.command = X25_READ_MODEM_STATUS; | ||
| 2150 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2151 | if (err){ | ||
| 2152 | x25_error(card, err, X25_READ_MODEM_STATUS, 0); | ||
| 2153 | }else{ | ||
| 2154 | |||
| 2155 | modem_status = (TX25ModemStatus*)mbox->data; | ||
| 2156 | |||
| 2157 | /* Check if the last status was the same | ||
| 2158 | * if it was, do NOT print message again */ | ||
| 2159 | |||
| 2160 | if (last_stat.status != modem_status->status){ | ||
| 2161 | |||
| 2162 | printk(KERN_INFO "%s: Modem Status Change: DCD=%s, CTS=%s\n", | ||
| 2163 | card->devname,DCD(modem_status->status),CTS(modem_status->status)); | ||
| 2164 | |||
| 2165 | last_stat.status = modem_status->status; | ||
| 2166 | |||
| 2167 | if (card->u.x.oob_on_modem){ | ||
| 2168 | |||
| 2169 | mbox->cmd.pktType = mbox->cmd.command; | ||
| 2170 | mbox->cmd.result = 0x08; | ||
| 2171 | |||
| 2172 | /* Send a OOB to all connected sockets */ | ||
| 2173 | for (dev = card->wandev.dev; dev; | ||
| 2174 | dev = *((struct net_device**)dev->priv)) { | ||
| 2175 | chan=dev->priv; | ||
| 2176 | if (chan->common.usedby == API){ | ||
| 2177 | send_oob_msg(card,dev,mbox); | ||
| 2178 | } | ||
| 2179 | } | ||
| 2180 | |||
| 2181 | /* The modem OOB message will probably kill the | ||
| 2182 | * the link. If we don't clear the flag here, | ||
| 2183 | * a deadlock could occur */ | ||
| 2184 | if (atomic_read(&card->u.x.command_busy)){ | ||
| 2185 | atomic_set(&card->u.x.command_busy,0); | ||
| 2186 | } | ||
| 2187 | } | ||
| 2188 | } | ||
| 2189 | } | ||
| 2190 | |||
| 2191 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
| 2192 | mbox->cmd.command = X25_HDLC_LINK_STATUS; | ||
| 2193 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2194 | if (err){ | ||
| 2195 | x25_error(card, err, X25_HDLC_LINK_STATUS, 0); | ||
| 2196 | } | ||
| 2197 | |||
| 2198 | } | ||
| 2199 | |||
| 2200 | /*==================================================================== | ||
| 2201 | * Network event interrupt handler. | ||
| 2202 | *===================================================================*/ | ||
| 2203 | static void event_intr (sdla_t* card) | ||
| 2204 | { | ||
| 2205 | x25_fetch_events(card); | ||
| 2206 | } | ||
| 2207 | |||
| 2208 | /*==================================================================== | ||
| 2209 | * Spurious interrupt handler. | ||
| 2210 | * o print a warning | ||
| 2211 | * o | ||
| 2212 | *====================================================================*/ | ||
| 2213 | |||
| 2214 | static void spur_intr (sdla_t* card) | ||
| 2215 | { | ||
| 2216 | printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); | ||
| 2217 | } | ||
| 2218 | |||
| 2219 | |||
| 2220 | /* | ||
| 2221 | * Background Polling Routines | ||
| 2222 | */ | ||
| 2223 | |||
| 2224 | /*==================================================================== | ||
| 2225 | * Main polling routine. | ||
| 2226 | * This routine is repeatedly called by the WANPIPE 'thread' to allow for | ||
| 2227 | * time-dependent housekeeping work. | ||
| 2228 | * | ||
| 2229 | * Notes: | ||
| 2230 | * 1. This routine may be called on interrupt context with all interrupts | ||
| 2231 | * enabled. Beware! | ||
| 2232 | *====================================================================*/ | ||
| 2233 | |||
| 2234 | static void wpx_poll (sdla_t *card) | ||
| 2235 | { | ||
| 2236 | if (!card->wandev.dev){ | ||
| 2237 | goto wpx_poll_exit; | ||
| 2238 | } | ||
| 2239 | |||
| 2240 | if (card->open_cnt != card->u.x.num_of_ch){ | ||
| 2241 | goto wpx_poll_exit; | ||
| 2242 | } | ||
| 2243 | |||
| 2244 | if (test_bit(PERI_CRIT,&card->wandev.critical)){ | ||
| 2245 | goto wpx_poll_exit; | ||
| 2246 | } | ||
| 2247 | |||
| 2248 | if (test_bit(SEND_CRIT,&card->wandev.critical)){ | ||
| 2249 | goto wpx_poll_exit; | ||
| 2250 | } | ||
| 2251 | |||
| 2252 | switch(card->wandev.state){ | ||
| 2253 | case WAN_CONNECTED: | ||
| 2254 | poll_active(card); | ||
| 2255 | break; | ||
| 2256 | |||
| 2257 | case WAN_CONNECTING: | ||
| 2258 | poll_connecting(card); | ||
| 2259 | break; | ||
| 2260 | |||
| 2261 | case WAN_DISCONNECTED: | ||
| 2262 | poll_disconnected(card); | ||
| 2263 | break; | ||
| 2264 | } | ||
| 2265 | |||
| 2266 | wpx_poll_exit: | ||
| 2267 | clear_bit(POLL_CRIT,&card->wandev.critical); | ||
| 2268 | return; | ||
| 2269 | } | ||
| 2270 | |||
| 2271 | static void trigger_x25_poll(sdla_t *card) | ||
| 2272 | { | ||
| 2273 | schedule_work(&card->u.x.x25_poll_work); | ||
| 2274 | } | ||
| 2275 | |||
| 2276 | /*==================================================================== | ||
| 2277 | * Handle physical link establishment phase. | ||
| 2278 | * o if connection timed out, disconnect the link. | ||
| 2279 | *===================================================================*/ | ||
| 2280 | |||
| 2281 | static void poll_connecting (sdla_t* card) | ||
| 2282 | { | ||
| 2283 | volatile TX25Status* status = card->flags; | ||
| 2284 | |||
| 2285 | if (status->gflags & X25_HDLC_ABM){ | ||
| 2286 | |||
| 2287 | timer_intr_exec (card, TMR_INT_ENABLED_POLL_CONNECT_ON); | ||
| 2288 | |||
| 2289 | }else if ((jiffies - card->state_tick) > CONNECT_TIMEOUT){ | ||
| 2290 | |||
| 2291 | timer_intr_exec (card, TMR_INT_ENABLED_POLL_CONNECT_OFF); | ||
| 2292 | |||
| 2293 | } | ||
| 2294 | } | ||
| 2295 | |||
| 2296 | /*==================================================================== | ||
| 2297 | * Handle physical link disconnected phase. | ||
| 2298 | * o if hold-down timeout has expired and there are open interfaces, | ||
| 2299 | * connect link. | ||
| 2300 | *===================================================================*/ | ||
| 2301 | |||
| 2302 | static void poll_disconnected (sdla_t* card) | ||
| 2303 | { | ||
| 2304 | struct net_device *dev; | ||
| 2305 | x25_channel_t *chan; | ||
| 2306 | TX25Status* status = card->flags; | ||
| 2307 | |||
| 2308 | if (!card->u.x.LAPB_hdlc && card->open_cnt && | ||
| 2309 | ((jiffies - card->state_tick) > HOLD_DOWN_TIME)){ | ||
| 2310 | timer_intr_exec(card, TMR_INT_ENABLED_POLL_DISCONNECT); | ||
| 2311 | } | ||
| 2312 | |||
| 2313 | |||
| 2314 | if ((dev=card->wandev.dev) == NULL) | ||
| 2315 | return; | ||
| 2316 | |||
| 2317 | if ((chan=dev->priv) == NULL) | ||
| 2318 | return; | ||
| 2319 | |||
| 2320 | if (chan->common.usedby == API && | ||
| 2321 | atomic_read(&chan->common.command) && | ||
| 2322 | card->u.x.LAPB_hdlc){ | ||
| 2323 | |||
| 2324 | if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC)) | ||
| 2325 | card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC; | ||
| 2326 | |||
| 2327 | if (!(status->imask & INTR_ON_TIMER)) | ||
| 2328 | status->imask |= INTR_ON_TIMER; | ||
| 2329 | } | ||
| 2330 | |||
| 2331 | } | ||
| 2332 | |||
| 2333 | /*==================================================================== | ||
| 2334 | * Handle active link phase. | ||
| 2335 | * o fetch X.25 asynchronous events. | ||
| 2336 | * o kick off transmission on all interfaces. | ||
| 2337 | *===================================================================*/ | ||
| 2338 | |||
| 2339 | static void poll_active (sdla_t* card) | ||
| 2340 | { | ||
| 2341 | struct net_device* dev; | ||
| 2342 | TX25Status* status = card->flags; | ||
| 2343 | |||
| 2344 | for (dev = card->wandev.dev; dev; | ||
| 2345 | dev = *((struct net_device **)dev->priv)){ | ||
| 2346 | x25_channel_t* chan = dev->priv; | ||
| 2347 | |||
| 2348 | /* If SVC has been idle long enough, close virtual circuit */ | ||
| 2349 | if ( chan->common.svc && | ||
| 2350 | chan->common.state == WAN_CONNECTED && | ||
| 2351 | chan->common.usedby == WANPIPE ){ | ||
| 2352 | |||
| 2353 | if( (jiffies - chan->i_timeout_sofar) / HZ > chan->idle_timeout ){ | ||
| 2354 | /* Close svc */ | ||
| 2355 | card->u.x.poll_device=dev; | ||
| 2356 | timer_intr_exec (card, TMR_INT_ENABLED_POLL_ACTIVE); | ||
| 2357 | } | ||
| 2358 | } | ||
| 2359 | |||
| 2360 | #ifdef PRINT_DEBUG | ||
| 2361 | chan->ifstats.tx_compressed = atomic_read(&chan->common.command); | ||
| 2362 | chan->ifstats.tx_errors = chan->common.state; | ||
| 2363 | chan->ifstats.rx_fifo_errors = atomic_read(&card->u.x.command_busy); | ||
| 2364 | ++chan->ifstats.tx_bytes; | ||
| 2365 | |||
| 2366 | chan->ifstats.rx_fifo_errors=atomic_read(&chan->common.disconnect); | ||
| 2367 | chan->ifstats.multicast=atomic_read(&chan->bh_buff_used); | ||
| 2368 | chan->ifstats.rx_length_errors=*card->u.x.hdlc_buf_status; | ||
| 2369 | #endif | ||
| 2370 | |||
| 2371 | if (chan->common.usedby == API && | ||
| 2372 | atomic_read(&chan->common.command) && | ||
| 2373 | !card->u.x.LAPB_hdlc){ | ||
| 2374 | |||
| 2375 | if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC)) | ||
| 2376 | card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC; | ||
| 2377 | |||
| 2378 | if (!(status->imask & INTR_ON_TIMER)) | ||
| 2379 | status->imask |= INTR_ON_TIMER; | ||
| 2380 | } | ||
| 2381 | |||
| 2382 | if ((chan->common.usedby == API) && | ||
| 2383 | atomic_read(&chan->common.disconnect)){ | ||
| 2384 | |||
| 2385 | if (chan->common.state == WAN_DISCONNECTED){ | ||
| 2386 | atomic_set(&chan->common.disconnect,0); | ||
| 2387 | return; | ||
| 2388 | } | ||
| 2389 | |||
| 2390 | atomic_set(&chan->common.command,X25_CLEAR_CALL); | ||
| 2391 | if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC)) | ||
| 2392 | card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC; | ||
| 2393 | |||
| 2394 | if (!(status->imask & INTR_ON_TIMER)) | ||
| 2395 | status->imask |= INTR_ON_TIMER; | ||
| 2396 | } | ||
| 2397 | } | ||
| 2398 | } | ||
| 2399 | |||
| 2400 | static void timer_intr_exec(sdla_t *card, unsigned char TYPE) | ||
| 2401 | { | ||
| 2402 | TX25Status* status = card->flags; | ||
| 2403 | card->u.x.timer_int_enabled |= TYPE; | ||
| 2404 | if (!(status->imask & INTR_ON_TIMER)) | ||
| 2405 | status->imask |= INTR_ON_TIMER; | ||
| 2406 | } | ||
| 2407 | |||
| 2408 | |||
| 2409 | /*==================================================================== | ||
| 2410 | * SDLA Firmware-Specific Functions | ||
| 2411 | * | ||
| 2412 | * Almost all X.25 commands can unexpetedly fail due to so called 'X.25 | ||
| 2413 | * asynchronous events' such as restart, interrupt, incoming call request, | ||
| 2414 | * call clear request, etc. They can't be ignored and have to be delt with | ||
| 2415 | * immediately. To tackle with this problem we execute each interface | ||
| 2416 | * command in a loop until good return code is received or maximum number | ||
| 2417 | * of retries is reached. Each interface command returns non-zero return | ||
| 2418 | * code, an asynchronous event/error handler x25_error() is called. | ||
| 2419 | *====================================================================*/ | ||
| 2420 | |||
| 2421 | /*==================================================================== | ||
| 2422 | * Read X.25 firmware version. | ||
| 2423 | * Put code version as ASCII string in str. | ||
| 2424 | *===================================================================*/ | ||
| 2425 | |||
| 2426 | static int x25_get_version (sdla_t* card, char* str) | ||
| 2427 | { | ||
| 2428 | TX25Mbox* mbox = card->mbox; | ||
| 2429 | int retry = MAX_CMD_RETRY; | ||
| 2430 | int err; | ||
| 2431 | |||
| 2432 | do | ||
| 2433 | { | ||
| 2434 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
| 2435 | mbox->cmd.command = X25_READ_CODE_VERSION; | ||
| 2436 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2437 | } while (err && retry-- && | ||
| 2438 | x25_error(card, err, X25_READ_CODE_VERSION, 0)); | ||
| 2439 | |||
| 2440 | if (!err && str) | ||
| 2441 | { | ||
| 2442 | int len = mbox->cmd.length; | ||
| 2443 | |||
| 2444 | memcpy(str, mbox->data, len); | ||
| 2445 | str[len] = '\0'; | ||
| 2446 | } | ||
| 2447 | return err; | ||
| 2448 | } | ||
| 2449 | |||
| 2450 | /*==================================================================== | ||
| 2451 | * Configure adapter. | ||
| 2452 | *===================================================================*/ | ||
| 2453 | |||
| 2454 | static int x25_configure (sdla_t* card, TX25Config* conf) | ||
| 2455 | { | ||
| 2456 | TX25Mbox* mbox = card->mbox; | ||
| 2457 | int retry = MAX_CMD_RETRY; | ||
| 2458 | int err; | ||
| 2459 | |||
| 2460 | do{ | ||
| 2461 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
| 2462 | memcpy(mbox->data, (void*)conf, sizeof(TX25Config)); | ||
| 2463 | mbox->cmd.length = sizeof(TX25Config); | ||
| 2464 | mbox->cmd.command = X25_SET_CONFIGURATION; | ||
| 2465 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2466 | } while (err && retry-- && x25_error(card, err, X25_SET_CONFIGURATION, 0)); | ||
| 2467 | return err; | ||
| 2468 | } | ||
| 2469 | |||
| 2470 | /*==================================================================== | ||
| 2471 | * Configure adapter for HDLC only. | ||
| 2472 | *===================================================================*/ | ||
| 2473 | |||
| 2474 | static int hdlc_configure (sdla_t* card, TX25Config* conf) | ||
| 2475 | { | ||
| 2476 | TX25Mbox* mbox = card->mbox; | ||
| 2477 | int retry = MAX_CMD_RETRY; | ||
| 2478 | int err; | ||
| 2479 | |||
| 2480 | do{ | ||
| 2481 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
| 2482 | memcpy(mbox->data, (void*)conf, sizeof(TX25Config)); | ||
| 2483 | mbox->cmd.length = sizeof(TX25Config); | ||
| 2484 | mbox->cmd.command = X25_HDLC_SET_CONFIG; | ||
| 2485 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2486 | } while (err && retry-- && x25_error(card, err, X25_SET_CONFIGURATION, 0)); | ||
| 2487 | |||
| 2488 | return err; | ||
| 2489 | } | ||
| 2490 | |||
| 2491 | static int set_hdlc_level (sdla_t* card) | ||
| 2492 | { | ||
| 2493 | |||
| 2494 | TX25Mbox* mbox = card->mbox; | ||
| 2495 | int retry = MAX_CMD_RETRY; | ||
| 2496 | int err; | ||
| 2497 | |||
| 2498 | do{ | ||
| 2499 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
| 2500 | mbox->cmd.command = SET_PROTOCOL_LEVEL; | ||
| 2501 | mbox->cmd.length = 1; | ||
| 2502 | mbox->data[0] = HDLC_LEVEL; //| DO_HDLC_LEVEL_ERROR_CHECKING; | ||
| 2503 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2504 | } while (err && retry-- && x25_error(card, err, SET_PROTOCOL_LEVEL, 0)); | ||
| 2505 | |||
| 2506 | return err; | ||
| 2507 | } | ||
| 2508 | |||
| 2509 | |||
| 2510 | |||
| 2511 | /*==================================================================== | ||
| 2512 | * Get communications error statistics. | ||
| 2513 | *====================================================================*/ | ||
| 2514 | |||
| 2515 | static int x25_get_err_stats (sdla_t* card) | ||
| 2516 | { | ||
| 2517 | TX25Mbox* mbox = card->mbox; | ||
| 2518 | int retry = MAX_CMD_RETRY; | ||
| 2519 | int err; | ||
| 2520 | |||
| 2521 | do | ||
| 2522 | { | ||
| 2523 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
| 2524 | mbox->cmd.command = X25_HDLC_READ_COMM_ERR; | ||
| 2525 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2526 | } while (err && retry-- && x25_error(card, err, X25_HDLC_READ_COMM_ERR, 0)); | ||
| 2527 | |||
| 2528 | if (!err) | ||
| 2529 | { | ||
| 2530 | THdlcCommErr* stats = (void*)mbox->data; | ||
| 2531 | |||
| 2532 | card->wandev.stats.rx_over_errors = stats->rxOverrun; | ||
| 2533 | card->wandev.stats.rx_crc_errors = stats->rxBadCrc; | ||
| 2534 | card->wandev.stats.rx_missed_errors = stats->rxAborted; | ||
| 2535 | card->wandev.stats.tx_aborted_errors = stats->txAborted; | ||
| 2536 | } | ||
| 2537 | return err; | ||
| 2538 | } | ||
| 2539 | |||
| 2540 | /*==================================================================== | ||
| 2541 | * Get protocol statistics. | ||
| 2542 | *===================================================================*/ | ||
| 2543 | |||
| 2544 | static int x25_get_stats (sdla_t* card) | ||
| 2545 | { | ||
| 2546 | TX25Mbox* mbox = card->mbox; | ||
| 2547 | int retry = MAX_CMD_RETRY; | ||
| 2548 | int err; | ||
| 2549 | |||
| 2550 | do | ||
| 2551 | { | ||
| 2552 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
| 2553 | mbox->cmd.command = X25_READ_STATISTICS; | ||
| 2554 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2555 | } while (err && retry-- && x25_error(card, err, X25_READ_STATISTICS, 0)) ; | ||
| 2556 | |||
| 2557 | if (!err) | ||
| 2558 | { | ||
| 2559 | TX25Stats* stats = (void*)mbox->data; | ||
| 2560 | |||
| 2561 | card->wandev.stats.rx_packets = stats->rxData; | ||
| 2562 | card->wandev.stats.tx_packets = stats->txData; | ||
| 2563 | } | ||
| 2564 | return err; | ||
| 2565 | } | ||
| 2566 | |||
| 2567 | /*==================================================================== | ||
| 2568 | * Close HDLC link. | ||
| 2569 | *===================================================================*/ | ||
| 2570 | |||
| 2571 | static int x25_close_hdlc (sdla_t* card) | ||
| 2572 | { | ||
| 2573 | TX25Mbox* mbox = card->mbox; | ||
| 2574 | int retry = MAX_CMD_RETRY; | ||
| 2575 | int err; | ||
| 2576 | |||
| 2577 | do | ||
| 2578 | { | ||
| 2579 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
| 2580 | mbox->cmd.command = X25_HDLC_LINK_CLOSE; | ||
| 2581 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2582 | } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_CLOSE, 0)); | ||
| 2583 | |||
| 2584 | return err; | ||
| 2585 | } | ||
| 2586 | |||
| 2587 | |||
| 2588 | /*==================================================================== | ||
| 2589 | * Open HDLC link. | ||
| 2590 | *===================================================================*/ | ||
| 2591 | |||
| 2592 | static int x25_open_hdlc (sdla_t* card) | ||
| 2593 | { | ||
| 2594 | TX25Mbox* mbox = card->mbox; | ||
| 2595 | int retry = MAX_CMD_RETRY; | ||
| 2596 | int err; | ||
| 2597 | |||
| 2598 | do | ||
| 2599 | { | ||
| 2600 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
| 2601 | mbox->cmd.command = X25_HDLC_LINK_OPEN; | ||
| 2602 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2603 | } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_OPEN, 0)); | ||
| 2604 | |||
| 2605 | return err; | ||
| 2606 | } | ||
| 2607 | |||
| 2608 | /*===================================================================== | ||
| 2609 | * Setup HDLC link. | ||
| 2610 | *====================================================================*/ | ||
| 2611 | static int x25_setup_hdlc (sdla_t* card) | ||
| 2612 | { | ||
| 2613 | TX25Mbox* mbox = card->mbox; | ||
| 2614 | int retry = MAX_CMD_RETRY; | ||
| 2615 | int err; | ||
| 2616 | |||
| 2617 | do | ||
| 2618 | { | ||
| 2619 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
| 2620 | mbox->cmd.command = X25_HDLC_LINK_SETUP; | ||
| 2621 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2622 | } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_SETUP, 0)); | ||
| 2623 | |||
| 2624 | return err; | ||
| 2625 | } | ||
| 2626 | |||
| 2627 | /*==================================================================== | ||
| 2628 | * Set (raise/drop) DTR. | ||
| 2629 | *===================================================================*/ | ||
| 2630 | |||
| 2631 | static int x25_set_dtr (sdla_t* card, int dtr) | ||
| 2632 | { | ||
| 2633 | TX25Mbox* mbox = card->mbox; | ||
| 2634 | int retry = MAX_CMD_RETRY; | ||
| 2635 | int err; | ||
| 2636 | |||
| 2637 | do | ||
| 2638 | { | ||
| 2639 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
| 2640 | mbox->data[0] = 0; | ||
| 2641 | mbox->data[2] = 0; | ||
| 2642 | mbox->data[1] = dtr ? 0x02 : 0x01; | ||
| 2643 | mbox->cmd.length = 3; | ||
| 2644 | mbox->cmd.command = X25_SET_GLOBAL_VARS; | ||
| 2645 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2646 | } while (err && retry-- && x25_error(card, err, X25_SET_GLOBAL_VARS, 0)); | ||
| 2647 | |||
| 2648 | return err; | ||
| 2649 | } | ||
| 2650 | |||
| 2651 | /*==================================================================== | ||
| 2652 | * Set interrupt mode. | ||
| 2653 | *===================================================================*/ | ||
| 2654 | |||
| 2655 | static int x25_set_intr_mode (sdla_t* card, int mode) | ||
| 2656 | { | ||
| 2657 | TX25Mbox* mbox = card->mbox; | ||
| 2658 | int retry = MAX_CMD_RETRY; | ||
| 2659 | int err; | ||
| 2660 | |||
| 2661 | do | ||
| 2662 | { | ||
| 2663 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
| 2664 | mbox->data[0] = mode; | ||
| 2665 | if (card->hw.fwid == SFID_X25_508){ | ||
| 2666 | mbox->data[1] = card->hw.irq; | ||
| 2667 | mbox->data[2] = 2; | ||
| 2668 | mbox->cmd.length = 3; | ||
| 2669 | }else { | ||
| 2670 | mbox->cmd.length = 1; | ||
| 2671 | } | ||
| 2672 | mbox->cmd.command = X25_SET_INTERRUPT_MODE; | ||
| 2673 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2674 | } while (err && retry-- && x25_error(card, err, X25_SET_INTERRUPT_MODE, 0)); | ||
| 2675 | |||
| 2676 | return err; | ||
| 2677 | } | ||
| 2678 | |||
| 2679 | /*==================================================================== | ||
| 2680 | * Read X.25 channel configuration. | ||
| 2681 | *===================================================================*/ | ||
| 2682 | |||
| 2683 | static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan) | ||
| 2684 | { | ||
| 2685 | TX25Mbox* mbox = card->mbox; | ||
| 2686 | int retry = MAX_CMD_RETRY; | ||
| 2687 | int lcn = chan->common.lcn; | ||
| 2688 | int err; | ||
| 2689 | |||
| 2690 | do{ | ||
| 2691 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
| 2692 | mbox->cmd.lcn = lcn; | ||
| 2693 | mbox->cmd.command = X25_READ_CHANNEL_CONFIG; | ||
| 2694 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2695 | } while (err && retry-- && x25_error(card, err, X25_READ_CHANNEL_CONFIG, lcn)); | ||
| 2696 | |||
| 2697 | if (!err) | ||
| 2698 | { | ||
| 2699 | TX25Status* status = card->flags; | ||
| 2700 | |||
| 2701 | /* calculate an offset into the array of status bytes */ | ||
| 2702 | if (card->u.x.hi_svc <= X25_MAX_CHAN){ | ||
| 2703 | |||
| 2704 | chan->ch_idx = lcn - 1; | ||
| 2705 | |||
| 2706 | }else{ | ||
| 2707 | int offset; | ||
| 2708 | |||
| 2709 | /* FIX: Apr 14 2000 : Nenad Corbic | ||
| 2710 | * The data field was being compared to 0x1F using | ||
| 2711 | * '&&' instead of '&'. | ||
| 2712 | * This caused X25API to fail for LCNs greater than 255. | ||
| 2713 | */ | ||
| 2714 | switch (mbox->data[0] & 0x1F) | ||
| 2715 | { | ||
| 2716 | case 0x01: | ||
| 2717 | offset = status->pvc_map; break; | ||
| 2718 | case 0x03: | ||
| 2719 | offset = status->icc_map; break; | ||
| 2720 | case 0x07: | ||
| 2721 | offset = status->twc_map; break; | ||
| 2722 | case 0x0B: | ||
| 2723 | offset = status->ogc_map; break; | ||
| 2724 | default: | ||
| 2725 | offset = 0; | ||
| 2726 | } | ||
| 2727 | chan->ch_idx = lcn - 1 - offset; | ||
| 2728 | } | ||
| 2729 | |||
| 2730 | /* get actual transmit packet size on this channel */ | ||
| 2731 | switch(mbox->data[1] & 0x38) | ||
| 2732 | { | ||
| 2733 | case 0x00: | ||
| 2734 | chan->tx_pkt_size = 16; | ||
| 2735 | break; | ||
| 2736 | case 0x08: | ||
| 2737 | chan->tx_pkt_size = 32; | ||
| 2738 | break; | ||
| 2739 | case 0x10: | ||
| 2740 | chan->tx_pkt_size = 64; | ||
| 2741 | break; | ||
| 2742 | case 0x18: | ||
| 2743 | chan->tx_pkt_size = 128; | ||
| 2744 | break; | ||
| 2745 | case 0x20: | ||
| 2746 | chan->tx_pkt_size = 256; | ||
| 2747 | break; | ||
| 2748 | case 0x28: | ||
| 2749 | chan->tx_pkt_size = 512; | ||
| 2750 | break; | ||
| 2751 | case 0x30: | ||
| 2752 | chan->tx_pkt_size = 1024; | ||
| 2753 | break; | ||
| 2754 | } | ||
| 2755 | if (card->u.x.logging) | ||
| 2756 | printk(KERN_INFO "%s: X.25 packet size on LCN %d is %d.\n", | ||
| 2757 | card->devname, lcn, chan->tx_pkt_size); | ||
| 2758 | } | ||
| 2759 | return err; | ||
| 2760 | } | ||
| 2761 | |||
| 2762 | /*==================================================================== | ||
| 2763 | * Place X.25 call. | ||
| 2764 | *====================================================================*/ | ||
| 2765 | |||
| 2766 | static int x25_place_call (sdla_t* card, x25_channel_t* chan) | ||
| 2767 | { | ||
| 2768 | TX25Mbox* mbox = card->mbox; | ||
| 2769 | int retry = MAX_CMD_RETRY; | ||
| 2770 | int err; | ||
| 2771 | char str[64]; | ||
| 2772 | |||
| 2773 | |||
| 2774 | if (chan->protocol == htons(ETH_P_IP)){ | ||
| 2775 | sprintf(str, "-d%s -uCC", chan->addr); | ||
| 2776 | |||
| 2777 | }else if (chan->protocol == htons(ETH_P_IPX)){ | ||
| 2778 | sprintf(str, "-d%s -u800000008137", chan->addr); | ||
| 2779 | |||
| 2780 | } | ||
| 2781 | |||
| 2782 | do | ||
| 2783 | { | ||
| 2784 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
| 2785 | strcpy(mbox->data, str); | ||
| 2786 | mbox->cmd.length = strlen(str); | ||
| 2787 | mbox->cmd.command = X25_PLACE_CALL; | ||
| 2788 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2789 | } while (err && retry-- && x25_error(card, err, X25_PLACE_CALL, 0)); | ||
| 2790 | |||
| 2791 | if (!err){ | ||
| 2792 | bind_lcn_to_dev (card, chan->dev, mbox->cmd.lcn); | ||
| 2793 | } | ||
| 2794 | return err; | ||
| 2795 | } | ||
| 2796 | |||
| 2797 | /*==================================================================== | ||
| 2798 | * Accept X.25 call. | ||
| 2799 | *====================================================================*/ | ||
| 2800 | |||
| 2801 | static int x25_accept_call (sdla_t* card, int lcn, int qdm) | ||
| 2802 | { | ||
| 2803 | TX25Mbox* mbox = card->mbox; | ||
| 2804 | int retry = MAX_CMD_RETRY; | ||
| 2805 | int err; | ||
| 2806 | |||
| 2807 | do | ||
| 2808 | { | ||
| 2809 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
| 2810 | mbox->cmd.lcn = lcn; | ||
| 2811 | mbox->cmd.qdm = qdm; | ||
| 2812 | mbox->cmd.command = X25_ACCEPT_CALL; | ||
| 2813 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2814 | } while (err && retry-- && x25_error(card, err, X25_ACCEPT_CALL, lcn)); | ||
| 2815 | |||
| 2816 | return err; | ||
| 2817 | } | ||
| 2818 | |||
| 2819 | /*==================================================================== | ||
| 2820 | * Clear X.25 call. | ||
| 2821 | *====================================================================*/ | ||
| 2822 | |||
| 2823 | static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn) | ||
| 2824 | { | ||
| 2825 | TX25Mbox* mbox = card->mbox; | ||
| 2826 | int retry = MAX_CMD_RETRY; | ||
| 2827 | int err; | ||
| 2828 | |||
| 2829 | do | ||
| 2830 | { | ||
| 2831 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
| 2832 | mbox->cmd.lcn = lcn; | ||
| 2833 | mbox->cmd.cause = cause; | ||
| 2834 | mbox->cmd.diagn = diagn; | ||
| 2835 | mbox->cmd.command = X25_CLEAR_CALL; | ||
| 2836 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2837 | } while (err && retry-- && x25_error(card, err, X25_CLEAR_CALL, lcn)); | ||
| 2838 | |||
| 2839 | return err; | ||
| 2840 | } | ||
| 2841 | |||
| 2842 | /*==================================================================== | ||
| 2843 | * Send X.25 data packet. | ||
| 2844 | *====================================================================*/ | ||
| 2845 | |||
| 2846 | static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf) | ||
| 2847 | { | ||
| 2848 | TX25Mbox* mbox = card->mbox; | ||
| 2849 | int retry = MAX_CMD_RETRY; | ||
| 2850 | int err; | ||
| 2851 | unsigned char cmd; | ||
| 2852 | |||
| 2853 | if (card->u.x.LAPB_hdlc) | ||
| 2854 | cmd = X25_HDLC_WRITE; | ||
| 2855 | else | ||
| 2856 | cmd = X25_WRITE; | ||
| 2857 | |||
| 2858 | do | ||
| 2859 | { | ||
| 2860 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
| 2861 | memcpy(mbox->data, buf, len); | ||
| 2862 | mbox->cmd.length = len; | ||
| 2863 | mbox->cmd.lcn = lcn; | ||
| 2864 | |||
| 2865 | if (card->u.x.LAPB_hdlc){ | ||
| 2866 | mbox->cmd.pf = qdm; | ||
| 2867 | }else{ | ||
| 2868 | mbox->cmd.qdm = qdm; | ||
| 2869 | } | ||
| 2870 | |||
| 2871 | mbox->cmd.command = cmd; | ||
| 2872 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2873 | } while (err && retry-- && x25_error(card, err, cmd , lcn)); | ||
| 2874 | |||
| 2875 | |||
| 2876 | /* If buffers are busy the return code for LAPB HDLC is | ||
| 2877 | * 1. The above functions are looking for return code | ||
| 2878 | * of X25RES_NOT_READY if busy. */ | ||
| 2879 | |||
| 2880 | if (card->u.x.LAPB_hdlc && err == 1){ | ||
| 2881 | err = X25RES_NOT_READY; | ||
| 2882 | } | ||
| 2883 | |||
| 2884 | return err; | ||
| 2885 | } | ||
| 2886 | |||
| 2887 | /*==================================================================== | ||
| 2888 | * Fetch X.25 asynchronous events. | ||
| 2889 | *===================================================================*/ | ||
| 2890 | |||
| 2891 | static int x25_fetch_events (sdla_t* card) | ||
| 2892 | { | ||
| 2893 | TX25Status* status = card->flags; | ||
| 2894 | TX25Mbox* mbox = card->mbox; | ||
| 2895 | int err = 0; | ||
| 2896 | |||
| 2897 | if (status->gflags & 0x20) | ||
| 2898 | { | ||
| 2899 | memset(&mbox->cmd, 0, sizeof(TX25Cmd)); | ||
| 2900 | mbox->cmd.command = X25_IS_DATA_AVAILABLE; | ||
| 2901 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 2902 | if (err) x25_error(card, err, X25_IS_DATA_AVAILABLE, 0); | ||
| 2903 | } | ||
| 2904 | return err; | ||
| 2905 | } | ||
| 2906 | |||
| 2907 | /*==================================================================== | ||
| 2908 | * X.25 asynchronous event/error handler. | ||
| 2909 | * This routine is called each time interface command returns | ||
| 2910 | * non-zero return code to handle X.25 asynchronous events and | ||
| 2911 | * common errors. Return non-zero to repeat command or zero to | ||
| 2912 | * cancel it. | ||
| 2913 | * | ||
| 2914 | * Notes: | ||
| 2915 | * 1. This function may be called recursively, as handling some of the | ||
| 2916 | * asynchronous events (e.g. call request) requires execution of the | ||
| 2917 | * interface command(s) that, in turn, may also return asynchronous | ||
| 2918 | * events. To avoid re-entrancy problems we copy mailbox to dynamically | ||
| 2919 | * allocated memory before processing events. | ||
| 2920 | *====================================================================*/ | ||
| 2921 | |||
| 2922 | static int x25_error (sdla_t* card, int err, int cmd, int lcn) | ||
| 2923 | { | ||
| 2924 | int retry = 1; | ||
| 2925 | unsigned dlen = ((TX25Mbox*)card->mbox)->cmd.length; | ||
| 2926 | TX25Mbox* mb; | ||
| 2927 | |||
| 2928 | mb = kmalloc(sizeof(TX25Mbox) + dlen, GFP_ATOMIC); | ||
| 2929 | if (mb == NULL) | ||
| 2930 | { | ||
| 2931 | printk(KERN_ERR "%s: x25_error() out of memory!\n", | ||
| 2932 | card->devname); | ||
| 2933 | return 0; | ||
| 2934 | } | ||
| 2935 | memcpy(mb, card->mbox, sizeof(TX25Mbox) + dlen); | ||
| 2936 | switch (err){ | ||
| 2937 | |||
| 2938 | case X25RES_ASYNC_PACKET: /* X.25 asynchronous packet was received */ | ||
| 2939 | |||
| 2940 | mb->data[dlen] = '\0'; | ||
| 2941 | |||
| 2942 | switch (mb->cmd.pktType & 0x7F){ | ||
| 2943 | |||
| 2944 | case ASE_CALL_RQST: /* incoming call */ | ||
| 2945 | retry = incoming_call(card, cmd, lcn, mb); | ||
| 2946 | break; | ||
| 2947 | |||
| 2948 | case ASE_CALL_ACCEPTED: /* connected */ | ||
| 2949 | retry = call_accepted(card, cmd, lcn, mb); | ||
| 2950 | break; | ||
| 2951 | |||
| 2952 | case ASE_CLEAR_RQST: /* call clear request */ | ||
| 2953 | retry = call_cleared(card, cmd, lcn, mb); | ||
| 2954 | break; | ||
| 2955 | |||
| 2956 | case ASE_RESET_RQST: /* reset request */ | ||
| 2957 | printk(KERN_INFO "%s: X.25 reset request on LCN %d! " | ||
| 2958 | "Cause:0x%02X Diagn:0x%02X\n", | ||
| 2959 | card->devname, mb->cmd.lcn, mb->cmd.cause, | ||
| 2960 | mb->cmd.diagn); | ||
| 2961 | api_oob_event (card,mb); | ||
| 2962 | break; | ||
| 2963 | |||
| 2964 | case ASE_RESTART_RQST: /* restart request */ | ||
| 2965 | retry = restart_event(card, cmd, lcn, mb); | ||
| 2966 | break; | ||
| 2967 | |||
| 2968 | case ASE_CLEAR_CONFRM: | ||
| 2969 | if (clear_confirm_event (card,mb)) | ||
| 2970 | break; | ||
| 2971 | |||
| 2972 | /* I use the goto statement here so if | ||
| 2973 | * somebody inserts code between the | ||
| 2974 | * case and default, we will not have | ||
| 2975 | * ghost problems */ | ||
| 2976 | |||
| 2977 | goto dflt_1; | ||
| 2978 | |||
| 2979 | default: | ||
| 2980 | dflt_1: | ||
| 2981 | printk(KERN_INFO "%s: X.25 event 0x%02X on LCN %d! " | ||
| 2982 | "Cause:0x%02X Diagn:0x%02X\n", | ||
| 2983 | card->devname, mb->cmd.pktType, | ||
| 2984 | mb->cmd.lcn, mb->cmd.cause, mb->cmd.diagn); | ||
| 2985 | } | ||
| 2986 | break; | ||
| 2987 | |||
| 2988 | case X25RES_PROTO_VIOLATION: /* X.25 protocol violation indication */ | ||
| 2989 | |||
| 2990 | /* Bug Fix: Mar 14 2000 | ||
| 2991 | * The Protocol violation error conditions were | ||
| 2992 | * not handled previously */ | ||
| 2993 | |||
| 2994 | switch (mb->cmd.pktType & 0x7F){ | ||
| 2995 | |||
| 2996 | case PVE_CLEAR_RQST: /* Clear request */ | ||
| 2997 | retry = call_cleared(card, cmd, lcn, mb); | ||
| 2998 | break; | ||
| 2999 | |||
| 3000 | case PVE_RESET_RQST: /* Reset request */ | ||
| 3001 | printk(KERN_INFO "%s: X.25 reset request on LCN %d! " | ||
| 3002 | "Cause:0x%02X Diagn:0x%02X\n", | ||
| 3003 | card->devname, mb->cmd.lcn, mb->cmd.cause, | ||
| 3004 | mb->cmd.diagn); | ||
| 3005 | api_oob_event (card,mb); | ||
| 3006 | break; | ||
| 3007 | |||
| 3008 | case PVE_RESTART_RQST: /* Restart request */ | ||
| 3009 | retry = restart_event(card, cmd, lcn, mb); | ||
| 3010 | break; | ||
| 3011 | |||
| 3012 | default : | ||
| 3013 | printk(KERN_INFO | ||
| 3014 | "%s: X.25 protocol violation on LCN %d! " | ||
| 3015 | "Packet:0x%02X Cause:0x%02X Diagn:0x%02X\n", | ||
| 3016 | card->devname, mb->cmd.lcn, | ||
| 3017 | mb->cmd.pktType & 0x7F, mb->cmd.cause, mb->cmd.diagn); | ||
| 3018 | api_oob_event(card,mb); | ||
| 3019 | } | ||
| 3020 | break; | ||
| 3021 | |||
| 3022 | case 0x42: /* X.25 timeout */ | ||
| 3023 | retry = timeout_event(card, cmd, lcn, mb); | ||
| 3024 | break; | ||
| 3025 | |||
| 3026 | case 0x43: /* X.25 retry limit exceeded */ | ||
| 3027 | printk(KERN_INFO | ||
| 3028 | "%s: exceeded X.25 retry limit on LCN %d! " | ||
| 3029 | "Packet:0x%02X Diagn:0x%02X\n", card->devname, | ||
| 3030 | mb->cmd.lcn, mb->cmd.pktType, mb->cmd.diagn) | ||
| 3031 | ; | ||
| 3032 | break; | ||
| 3033 | |||
| 3034 | case 0x08: /* modem failure */ | ||
| 3035 | #ifndef MODEM_NOT_LOG | ||
| 3036 | printk(KERN_INFO "%s: modem failure!\n", card->devname); | ||
| 3037 | #endif /* MODEM_NOT_LOG */ | ||
| 3038 | api_oob_event(card,mb); | ||
| 3039 | break; | ||
| 3040 | |||
| 3041 | case 0x09: /* N2 retry limit */ | ||
| 3042 | printk(KERN_INFO "%s: exceeded HDLC retry limit!\n", | ||
| 3043 | card->devname); | ||
| 3044 | api_oob_event(card,mb); | ||
| 3045 | break; | ||
| 3046 | |||
| 3047 | case 0x06: /* unnumbered frame was received while in ABM */ | ||
| 3048 | printk(KERN_INFO "%s: received Unnumbered frame 0x%02X!\n", | ||
| 3049 | card->devname, mb->data[0]); | ||
| 3050 | api_oob_event(card,mb); | ||
| 3051 | break; | ||
| 3052 | |||
| 3053 | case CMD_TIMEOUT: | ||
| 3054 | printk(KERN_ERR "%s: command 0x%02X timed out!\n", | ||
| 3055 | card->devname, cmd) | ||
| 3056 | ; | ||
| 3057 | retry = 0; /* abort command */ | ||
| 3058 | break; | ||
| 3059 | |||
| 3060 | case X25RES_NOT_READY: | ||
| 3061 | retry = 1; | ||
| 3062 | break; | ||
| 3063 | |||
| 3064 | case 0x01: | ||
| 3065 | if (card->u.x.LAPB_hdlc) | ||
| 3066 | break; | ||
| 3067 | |||
| 3068 | if (mb->cmd.command == 0x16) | ||
| 3069 | break; | ||
| 3070 | /* I use the goto statement here so if | ||
| 3071 | * somebody inserts code between the | ||
| 3072 | * case and default, we will not have | ||
| 3073 | * ghost problems */ | ||
| 3074 | goto dflt_2; | ||
| 3075 | |||
| 3076 | default: | ||
| 3077 | dflt_2: | ||
| 3078 | printk(KERN_INFO "%s: command 0x%02X returned 0x%02X! Lcn %i\n", | ||
| 3079 | card->devname, cmd, err, mb->cmd.lcn) | ||
| 3080 | ; | ||
| 3081 | retry = 0; /* abort command */ | ||
| 3082 | } | ||
| 3083 | kfree(mb); | ||
| 3084 | return retry; | ||
| 3085 | } | ||
| 3086 | |||
| 3087 | /*==================================================================== | ||
| 3088 | * X.25 Asynchronous Event Handlers | ||
| 3089 | * These functions are called by the x25_error() and should return 0, if | ||
| 3090 | * the command resulting in the asynchronous event must be aborted. | ||
| 3091 | *====================================================================*/ | ||
| 3092 | |||
| 3093 | |||
| 3094 | |||
| 3095 | /*==================================================================== | ||
| 3096 | *Handle X.25 incoming call request. | ||
| 3097 | * RFC 1356 establishes the following rules: | ||
| 3098 | * 1. The first octet in the Call User Data (CUD) field of the call | ||
| 3099 | * request packet contains NLPID identifying protocol encapsulation | ||
| 3100 | * 2. Calls MUST NOT be accepted unless router supports requested | ||
| 3101 | * protocol encapsulation. | ||
| 3102 | * 3. A diagnostic code 249 defined by ISO/IEC 8208 may be used | ||
| 3103 | * when clearing a call because protocol encapsulation is not | ||
| 3104 | * supported. | ||
| 3105 | * 4. If an incoming call is received while a call request is | ||
| 3106 | * pending (i.e. call collision has occurred), the incoming call | ||
| 3107 | * shall be rejected and call request shall be retried. | ||
| 3108 | *====================================================================*/ | ||
| 3109 | |||
| 3110 | static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) | ||
| 3111 | { | ||
| 3112 | struct wan_device* wandev = &card->wandev; | ||
| 3113 | int new_lcn = mb->cmd.lcn; | ||
| 3114 | struct net_device* dev = get_dev_by_lcn(wandev, new_lcn); | ||
| 3115 | x25_channel_t* chan = NULL; | ||
| 3116 | int accept = 0; /* set to '1' if o.k. to accept call */ | ||
| 3117 | unsigned int user_data; | ||
| 3118 | x25_call_info_t* info; | ||
| 3119 | |||
| 3120 | /* Make sure there is no call collision */ | ||
| 3121 | if (dev != NULL) | ||
| 3122 | { | ||
| 3123 | printk(KERN_INFO | ||
| 3124 | "%s: X.25 incoming call collision on LCN %d!\n", | ||
| 3125 | card->devname, new_lcn); | ||
| 3126 | |||
| 3127 | x25_clear_call(card, new_lcn, 0, 0); | ||
| 3128 | return 1; | ||
| 3129 | } | ||
| 3130 | |||
| 3131 | /* Make sure D bit is not set in call request */ | ||
| 3132 | //FIXME: THIS IS NOT TURE !!!! TAKE IT OUT | ||
| 3133 | // if (mb->cmd.qdm & 0x02) | ||
| 3134 | // { | ||
| 3135 | // printk(KERN_INFO | ||
| 3136 | // "%s: X.25 incoming call on LCN %d with D-bit set!\n", | ||
| 3137 | // card->devname, new_lcn); | ||
| 3138 | // | ||
| 3139 | // x25_clear_call(card, new_lcn, 0, 0); | ||
| 3140 | // return 1; | ||
| 3141 | // } | ||
| 3142 | |||
| 3143 | /* Parse call request data */ | ||
| 3144 | info = kmalloc(sizeof(x25_call_info_t), GFP_ATOMIC); | ||
| 3145 | if (info == NULL) | ||
| 3146 | { | ||
| 3147 | printk(KERN_ERR | ||
| 3148 | "%s: not enough memory to parse X.25 incoming call " | ||
| 3149 | "on LCN %d!\n", card->devname, new_lcn); | ||
| 3150 | x25_clear_call(card, new_lcn, 0, 0); | ||
| 3151 | return 1; | ||
| 3152 | } | ||
| 3153 | |||
| 3154 | parse_call_info(mb->data, info); | ||
| 3155 | |||
| 3156 | if (card->u.x.logging) | ||
| 3157 | printk(KERN_INFO "\n%s: X.25 incoming call on LCN %d!\n", | ||
| 3158 | card->devname, new_lcn); | ||
| 3159 | |||
| 3160 | /* Conver the first two ASCII characters into an | ||
| 3161 | * interger. Used to check the incoming protocol | ||
| 3162 | */ | ||
| 3163 | user_data = hex_to_uint(info->user,2); | ||
| 3164 | |||
| 3165 | /* Find available channel */ | ||
| 3166 | for (dev = wandev->dev; dev; dev = *((struct net_device **)dev->priv)) { | ||
| 3167 | chan = dev->priv; | ||
| 3168 | |||
| 3169 | if (chan->common.usedby == API) | ||
| 3170 | continue; | ||
| 3171 | |||
| 3172 | if (!chan->common.svc || (chan->common.state != WAN_DISCONNECTED)) | ||
| 3173 | continue; | ||
| 3174 | |||
| 3175 | if (user_data == NLPID_IP && chan->protocol != htons(ETH_P_IP)){ | ||
| 3176 | printk(KERN_INFO "IP packet but configured for IPX : %x, %x\n", | ||
| 3177 | htons(chan->protocol), info->user[0]); | ||
| 3178 | continue; | ||
| 3179 | } | ||
| 3180 | |||
| 3181 | if (user_data == NLPID_SNAP && chan->protocol != htons(ETH_P_IPX)){ | ||
| 3182 | printk(KERN_INFO "IPX packet but configured for IP: %x\n", | ||
| 3183 | htons(chan->protocol)); | ||
| 3184 | continue; | ||
| 3185 | } | ||
| 3186 | if (strcmp(info->src, chan->addr) == 0) | ||
| 3187 | break; | ||
| 3188 | |||
| 3189 | /* If just an '@' is specified, accept all incoming calls */ | ||
| 3190 | if (strcmp(chan->addr, "") == 0) | ||
| 3191 | break; | ||
| 3192 | } | ||
| 3193 | |||
| 3194 | if (dev == NULL){ | ||
| 3195 | |||
| 3196 | /* If the call is not for any WANPIPE interfaces | ||
| 3197 | * check to see if there is an API listening queue | ||
| 3198 | * waiting for data. If there is send the packet | ||
| 3199 | * up the stack. | ||
| 3200 | */ | ||
| 3201 | if (card->sk != NULL && card->func != NULL){ | ||
| 3202 | if (api_incoming_call(card,mb,new_lcn)){ | ||
| 3203 | x25_clear_call(card, new_lcn, 0, 0); | ||
| 3204 | } | ||
| 3205 | accept = 0; | ||
| 3206 | }else{ | ||
| 3207 | printk(KERN_INFO "%s: no channels available!\n", | ||
| 3208 | card->devname); | ||
| 3209 | |||
| 3210 | x25_clear_call(card, new_lcn, 0, 0); | ||
| 3211 | } | ||
| 3212 | |||
| 3213 | }else if (info->nuser == 0){ | ||
| 3214 | |||
| 3215 | printk(KERN_INFO | ||
| 3216 | "%s: no user data in incoming call on LCN %d!\n", | ||
| 3217 | card->devname, new_lcn) | ||
| 3218 | ; | ||
| 3219 | x25_clear_call(card, new_lcn, 0, 0); | ||
| 3220 | |||
| 3221 | }else switch (info->user[0]){ | ||
| 3222 | |||
| 3223 | case 0: /* multiplexed */ | ||
| 3224 | chan->protocol = htons(0); | ||
| 3225 | accept = 1; | ||
| 3226 | break; | ||
| 3227 | |||
| 3228 | case NLPID_IP: /* IP datagrams */ | ||
| 3229 | accept = 1; | ||
| 3230 | break; | ||
| 3231 | |||
| 3232 | case NLPID_SNAP: /* IPX datagrams */ | ||
| 3233 | accept = 1; | ||
| 3234 | break; | ||
| 3235 | |||
| 3236 | default: | ||
| 3237 | printk(KERN_INFO | ||
| 3238 | "%s: unsupported NLPID 0x%02X in incoming call " | ||
| 3239 | "on LCN %d!\n", card->devname, info->user[0], new_lcn); | ||
| 3240 | x25_clear_call(card, new_lcn, 0, 249); | ||
| 3241 | } | ||
| 3242 | |||
| 3243 | if (accept && (x25_accept_call(card, new_lcn, 0) == CMD_OK)){ | ||
| 3244 | |||
| 3245 | bind_lcn_to_dev (card, chan->dev, new_lcn); | ||
| 3246 | |||
| 3247 | if (x25_get_chan_conf(card, chan) == CMD_OK) | ||
| 3248 | set_chan_state(dev, WAN_CONNECTED); | ||
| 3249 | else | ||
| 3250 | x25_clear_call(card, new_lcn, 0, 0); | ||
| 3251 | } | ||
| 3252 | kfree(info); | ||
| 3253 | return 1; | ||
| 3254 | } | ||
| 3255 | |||
| 3256 | /*==================================================================== | ||
| 3257 | * Handle accepted call. | ||
| 3258 | *====================================================================*/ | ||
| 3259 | |||
| 3260 | static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) | ||
| 3261 | { | ||
| 3262 | unsigned new_lcn = mb->cmd.lcn; | ||
| 3263 | struct net_device* dev = find_channel(card, new_lcn); | ||
| 3264 | x25_channel_t* chan; | ||
| 3265 | |||
| 3266 | if (dev == NULL){ | ||
| 3267 | printk(KERN_INFO | ||
| 3268 | "%s: clearing orphaned connection on LCN %d!\n", | ||
| 3269 | card->devname, new_lcn); | ||
| 3270 | x25_clear_call(card, new_lcn, 0, 0); | ||
| 3271 | return 1; | ||
| 3272 | } | ||
| 3273 | |||
| 3274 | if (card->u.x.logging) | ||
| 3275 | printk(KERN_INFO "%s: X.25 call accepted on Dev %s and LCN %d!\n", | ||
| 3276 | card->devname, dev->name, new_lcn); | ||
| 3277 | |||
| 3278 | /* Get channel configuration and notify router */ | ||
| 3279 | chan = dev->priv; | ||
| 3280 | if (x25_get_chan_conf(card, chan) != CMD_OK) | ||
| 3281 | { | ||
| 3282 | x25_clear_call(card, new_lcn, 0, 0); | ||
| 3283 | return 1; | ||
| 3284 | } | ||
| 3285 | |||
| 3286 | set_chan_state(dev, WAN_CONNECTED); | ||
| 3287 | |||
| 3288 | if (chan->common.usedby == API){ | ||
| 3289 | send_delayed_cmd_result(card,dev,mb); | ||
| 3290 | bind_lcn_to_dev (card, dev, new_lcn); | ||
| 3291 | } | ||
| 3292 | |||
| 3293 | return 1; | ||
| 3294 | } | ||
| 3295 | |||
| 3296 | /*==================================================================== | ||
| 3297 | * Handle cleared call. | ||
| 3298 | *====================================================================*/ | ||
| 3299 | |||
| 3300 | static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) | ||
| 3301 | { | ||
| 3302 | unsigned new_lcn = mb->cmd.lcn; | ||
| 3303 | struct net_device* dev = find_channel(card, new_lcn); | ||
| 3304 | x25_channel_t *chan; | ||
| 3305 | unsigned char old_state; | ||
| 3306 | |||
| 3307 | if (card->u.x.logging){ | ||
| 3308 | printk(KERN_INFO "%s: X.25 clear request on LCN %d! Cause:0x%02X " | ||
| 3309 | "Diagn:0x%02X\n", | ||
| 3310 | card->devname, new_lcn, mb->cmd.cause, mb->cmd.diagn); | ||
| 3311 | } | ||
| 3312 | |||
| 3313 | if (dev == NULL){ | ||
| 3314 | printk(KERN_INFO "%s: X.25 clear request : No device for clear\n", | ||
| 3315 | card->devname); | ||
| 3316 | return 1; | ||
| 3317 | } | ||
| 3318 | |||
| 3319 | chan=dev->priv; | ||
| 3320 | |||
| 3321 | old_state = chan->common.state; | ||
| 3322 | |||
| 3323 | set_chan_state(dev, WAN_DISCONNECTED); | ||
| 3324 | |||
| 3325 | if (chan->common.usedby == API){ | ||
| 3326 | |||
| 3327 | switch (old_state){ | ||
| 3328 | |||
| 3329 | case WAN_CONNECTING: | ||
| 3330 | send_delayed_cmd_result(card,dev,mb); | ||
| 3331 | break; | ||
| 3332 | case WAN_CONNECTED: | ||
| 3333 | send_oob_msg(card,dev,mb); | ||
| 3334 | break; | ||
| 3335 | } | ||
| 3336 | } | ||
| 3337 | |||
| 3338 | return ((cmd == X25_WRITE) && (lcn == new_lcn)) ? 0 : 1; | ||
| 3339 | } | ||
| 3340 | |||
| 3341 | /*==================================================================== | ||
| 3342 | * Handle X.25 restart event. | ||
| 3343 | *====================================================================*/ | ||
| 3344 | |||
| 3345 | static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) | ||
| 3346 | { | ||
| 3347 | struct wan_device* wandev = &card->wandev; | ||
| 3348 | struct net_device* dev; | ||
| 3349 | x25_channel_t *chan; | ||
| 3350 | unsigned char old_state; | ||
| 3351 | |||
| 3352 | printk(KERN_INFO | ||
| 3353 | "%s: X.25 restart request! Cause:0x%02X Diagn:0x%02X\n", | ||
| 3354 | card->devname, mb->cmd.cause, mb->cmd.diagn); | ||
| 3355 | |||
| 3356 | /* down all logical channels */ | ||
| 3357 | for (dev = wandev->dev; dev; dev = *((struct net_device **)dev->priv)) { | ||
| 3358 | chan=dev->priv; | ||
| 3359 | old_state = chan->common.state; | ||
| 3360 | |||
| 3361 | set_chan_state(dev, WAN_DISCONNECTED); | ||
| 3362 | |||
| 3363 | if (chan->common.usedby == API){ | ||
| 3364 | switch (old_state){ | ||
| 3365 | |||
| 3366 | case WAN_CONNECTING: | ||
| 3367 | send_delayed_cmd_result(card,dev,mb); | ||
| 3368 | break; | ||
| 3369 | case WAN_CONNECTED: | ||
| 3370 | send_oob_msg(card,dev,mb); | ||
| 3371 | break; | ||
| 3372 | } | ||
| 3373 | } | ||
| 3374 | } | ||
| 3375 | return (cmd == X25_WRITE) ? 0 : 1; | ||
| 3376 | } | ||
| 3377 | |||
| 3378 | /*==================================================================== | ||
| 3379 | * Handle timeout event. | ||
| 3380 | *====================================================================*/ | ||
| 3381 | |||
| 3382 | static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) | ||
| 3383 | { | ||
| 3384 | unsigned new_lcn = mb->cmd.lcn; | ||
| 3385 | |||
| 3386 | if (mb->cmd.pktType == 0x05) /* call request time out */ | ||
| 3387 | { | ||
| 3388 | struct net_device* dev = find_channel(card,new_lcn); | ||
| 3389 | |||
| 3390 | printk(KERN_INFO "%s: X.25 call timed timeout on LCN %d!\n", | ||
| 3391 | card->devname, new_lcn); | ||
| 3392 | |||
| 3393 | if (dev){ | ||
| 3394 | x25_channel_t *chan = dev->priv; | ||
| 3395 | set_chan_state(dev, WAN_DISCONNECTED); | ||
| 3396 | |||
| 3397 | if (chan->common.usedby == API){ | ||
| 3398 | send_delayed_cmd_result(card,dev,card->mbox); | ||
| 3399 | } | ||
| 3400 | } | ||
| 3401 | }else{ | ||
| 3402 | printk(KERN_INFO "%s: X.25 packet 0x%02X timeout on LCN %d!\n", | ||
| 3403 | card->devname, mb->cmd.pktType, new_lcn); | ||
| 3404 | } | ||
| 3405 | return 1; | ||
| 3406 | } | ||
| 3407 | |||
| 3408 | /* | ||
| 3409 | * Miscellaneous | ||
| 3410 | */ | ||
| 3411 | |||
| 3412 | /*==================================================================== | ||
| 3413 | * Establish physical connection. | ||
| 3414 | * o open HDLC and raise DTR | ||
| 3415 | * | ||
| 3416 | * Return: 0 connection established | ||
| 3417 | * 1 connection is in progress | ||
| 3418 | * <0 error | ||
| 3419 | *===================================================================*/ | ||
| 3420 | |||
| 3421 | static int connect (sdla_t* card) | ||
| 3422 | { | ||
| 3423 | TX25Status* status = card->flags; | ||
| 3424 | |||
| 3425 | if (x25_open_hdlc(card) || x25_setup_hdlc(card)) | ||
| 3426 | return -EIO; | ||
| 3427 | |||
| 3428 | wanpipe_set_state(card, WAN_CONNECTING); | ||
| 3429 | |||
| 3430 | x25_set_intr_mode(card, INTR_ON_TIMER); | ||
| 3431 | status->imask &= ~INTR_ON_TIMER; | ||
| 3432 | |||
| 3433 | return 1; | ||
| 3434 | } | ||
| 3435 | |||
| 3436 | /* | ||
| 3437 | * Tear down physical connection. | ||
| 3438 | * o close HDLC link | ||
| 3439 | * o drop DTR | ||
| 3440 | * | ||
| 3441 | * Return: 0 | ||
| 3442 | * <0 error | ||
| 3443 | */ | ||
| 3444 | |||
| 3445 | static int disconnect (sdla_t* card) | ||
| 3446 | { | ||
| 3447 | wanpipe_set_state(card, WAN_DISCONNECTED); | ||
| 3448 | x25_set_intr_mode(card, INTR_ON_TIMER); /* disable all interrupt except timer */ | ||
| 3449 | x25_close_hdlc(card); /* close HDLC link */ | ||
| 3450 | x25_set_dtr(card, 0); /* drop DTR */ | ||
| 3451 | return 0; | ||
| 3452 | } | ||
| 3453 | |||
| 3454 | /* | ||
| 3455 | * Find network device by its channel number. | ||
| 3456 | */ | ||
| 3457 | |||
| 3458 | static struct net_device* get_dev_by_lcn(struct wan_device* wandev, | ||
| 3459 | unsigned lcn) | ||
| 3460 | { | ||
| 3461 | struct net_device* dev; | ||
| 3462 | |||
| 3463 | for (dev = wandev->dev; dev; dev = *((struct net_device **)dev->priv)) | ||
| 3464 | if (((x25_channel_t*)dev->priv)->common.lcn == lcn) | ||
| 3465 | break; | ||
| 3466 | return dev; | ||
| 3467 | } | ||
| 3468 | |||
| 3469 | /* | ||
| 3470 | * Initiate connection on the logical channel. | ||
| 3471 | * o for PVC we just get channel configuration | ||
| 3472 | * o for SVCs place an X.25 call | ||
| 3473 | * | ||
| 3474 | * Return: 0 connected | ||
| 3475 | * >0 connection in progress | ||
| 3476 | * <0 failure | ||
| 3477 | */ | ||
| 3478 | |||
| 3479 | static int chan_connect(struct net_device* dev) | ||
| 3480 | { | ||
| 3481 | x25_channel_t* chan = dev->priv; | ||
| 3482 | sdla_t* card = chan->card; | ||
| 3483 | |||
| 3484 | if (chan->common.svc && chan->common.usedby == WANPIPE){ | ||
| 3485 | if (!chan->addr[0]){ | ||
| 3486 | printk(KERN_INFO "%s: No Destination Address\n", | ||
| 3487 | card->devname); | ||
| 3488 | return -EINVAL; /* no destination address */ | ||
| 3489 | } | ||
| 3490 | printk(KERN_INFO "%s: placing X.25 call to %s ...\n", | ||
| 3491 | card->devname, chan->addr); | ||
| 3492 | |||
| 3493 | if (x25_place_call(card, chan) != CMD_OK) | ||
| 3494 | return -EIO; | ||
| 3495 | |||
| 3496 | set_chan_state(dev, WAN_CONNECTING); | ||
| 3497 | return 1; | ||
| 3498 | }else{ | ||
| 3499 | if (x25_get_chan_conf(card, chan) != CMD_OK) | ||
| 3500 | return -EIO; | ||
| 3501 | |||
| 3502 | set_chan_state(dev, WAN_CONNECTED); | ||
| 3503 | } | ||
| 3504 | return 0; | ||
| 3505 | } | ||
| 3506 | |||
| 3507 | /* | ||
| 3508 | * Disconnect logical channel. | ||
| 3509 | * o if SVC then clear X.25 call | ||
| 3510 | */ | ||
| 3511 | |||
| 3512 | static int chan_disc(struct net_device* dev) | ||
| 3513 | { | ||
| 3514 | x25_channel_t* chan = dev->priv; | ||
| 3515 | |||
| 3516 | if (chan->common.svc){ | ||
| 3517 | x25_clear_call(chan->card, chan->common.lcn, 0, 0); | ||
| 3518 | |||
| 3519 | /* For API we disconnect on clear | ||
| 3520 | * confirmation. | ||
| 3521 | */ | ||
| 3522 | if (chan->common.usedby == API) | ||
| 3523 | return 0; | ||
| 3524 | } | ||
| 3525 | |||
| 3526 | set_chan_state(dev, WAN_DISCONNECTED); | ||
| 3527 | |||
| 3528 | return 0; | ||
| 3529 | } | ||
| 3530 | |||
| 3531 | /* | ||
| 3532 | * Set logical channel state. | ||
| 3533 | */ | ||
| 3534 | |||
| 3535 | static void set_chan_state(struct net_device* dev, int state) | ||
| 3536 | { | ||
| 3537 | x25_channel_t* chan = dev->priv; | ||
| 3538 | sdla_t* card = chan->card; | ||
| 3539 | unsigned long flags; | ||
| 3540 | |||
| 3541 | save_flags(flags); | ||
| 3542 | cli(); | ||
| 3543 | if (chan->common.state != state) | ||
| 3544 | { | ||
| 3545 | switch (state) | ||
| 3546 | { | ||
| 3547 | case WAN_CONNECTED: | ||
| 3548 | if (card->u.x.logging){ | ||
| 3549 | printk (KERN_INFO | ||
| 3550 | "%s: interface %s connected, lcn %i !\n", | ||
| 3551 | card->devname, dev->name,chan->common.lcn); | ||
| 3552 | } | ||
| 3553 | *(unsigned short*)dev->dev_addr = htons(chan->common.lcn); | ||
| 3554 | chan->i_timeout_sofar = jiffies; | ||
| 3555 | |||
| 3556 | /* LAPB is PVC Based */ | ||
| 3557 | if (card->u.x.LAPB_hdlc) | ||
| 3558 | chan->common.svc=0; | ||
| 3559 | break; | ||
| 3560 | |||
| 3561 | case WAN_CONNECTING: | ||
| 3562 | if (card->u.x.logging){ | ||
| 3563 | printk (KERN_INFO | ||
| 3564 | "%s: interface %s connecting, lcn %i ...\n", | ||
| 3565 | card->devname, dev->name, chan->common.lcn); | ||
| 3566 | } | ||
| 3567 | break; | ||
| 3568 | |||
| 3569 | case WAN_DISCONNECTED: | ||
| 3570 | if (card->u.x.logging){ | ||
| 3571 | printk (KERN_INFO | ||
| 3572 | "%s: interface %s disconnected, lcn %i !\n", | ||
| 3573 | card->devname, dev->name,chan->common.lcn); | ||
| 3574 | } | ||
| 3575 | atomic_set(&chan->common.disconnect,0); | ||
| 3576 | |||
| 3577 | if (chan->common.svc) { | ||
| 3578 | *(unsigned short*)dev->dev_addr = 0; | ||
| 3579 | card->u.x.svc_to_dev_map[(chan->common.lcn%X25_MAX_CHAN)]=NULL; | ||
| 3580 | chan->common.lcn = 0; | ||
| 3581 | } | ||
| 3582 | |||
| 3583 | if (chan->transmit_length){ | ||
| 3584 | chan->transmit_length=0; | ||
| 3585 | atomic_set(&chan->common.driver_busy,0); | ||
| 3586 | chan->tx_offset=0; | ||
| 3587 | if (netif_queue_stopped(dev)){ | ||
| 3588 | netif_wake_queue(dev); | ||
| 3589 | } | ||
| 3590 | } | ||
| 3591 | atomic_set(&chan->common.command,0); | ||
| 3592 | break; | ||
| 3593 | |||
| 3594 | case WAN_DISCONNECTING: | ||
| 3595 | if (card->u.x.logging){ | ||
| 3596 | printk (KERN_INFO | ||
| 3597 | "\n%s: interface %s disconnecting, lcn %i ...\n", | ||
| 3598 | card->devname, dev->name,chan->common.lcn); | ||
| 3599 | } | ||
| 3600 | atomic_set(&chan->common.disconnect,0); | ||
| 3601 | break; | ||
| 3602 | } | ||
| 3603 | chan->common.state = state; | ||
| 3604 | } | ||
| 3605 | chan->state_tick = jiffies; | ||
| 3606 | restore_flags(flags); | ||
| 3607 | } | ||
| 3608 | |||
| 3609 | /* | ||
| 3610 | * Send packet on a logical channel. | ||
| 3611 | * When this function is called, tx_skb field of the channel data | ||
| 3612 | * space points to the transmit socket buffer. When transmission | ||
| 3613 | * is complete, release socket buffer and reset 'tbusy' flag. | ||
| 3614 | * | ||
| 3615 | * Return: 0 - transmission complete | ||
| 3616 | * 1 - busy | ||
| 3617 | * | ||
| 3618 | * Notes: | ||
| 3619 | * 1. If packet length is greater than MTU for this channel, we'll fragment | ||
| 3620 | * the packet into 'complete sequence' using M-bit. | ||
| 3621 | * 2. When transmission is complete, an event notification should be issued | ||
| 3622 | * to the router. | ||
| 3623 | */ | ||
| 3624 | |||
| 3625 | static int chan_send(struct net_device* dev, void* buff, unsigned data_len, | ||
| 3626 | unsigned char tx_intr) | ||
| 3627 | { | ||
| 3628 | x25_channel_t* chan = dev->priv; | ||
| 3629 | sdla_t* card = chan->card; | ||
| 3630 | TX25Status* status = card->flags; | ||
| 3631 | unsigned len=0, qdm=0, res=0, orig_len = 0; | ||
| 3632 | void *data; | ||
| 3633 | |||
| 3634 | /* Check to see if channel is ready */ | ||
| 3635 | if ((!(status->cflags[chan->ch_idx] & 0x40) && !card->u.x.LAPB_hdlc) || | ||
| 3636 | !(*card->u.x.hdlc_buf_status & 0x40)){ | ||
| 3637 | |||
| 3638 | if (!tx_intr){ | ||
| 3639 | setup_for_delayed_transmit (dev, buff, data_len); | ||
| 3640 | return 0; | ||
| 3641 | }else{ | ||
| 3642 | /* By returning 0 to tx_intr the packet will be dropped */ | ||
| 3643 | ++card->wandev.stats.tx_dropped; | ||
| 3644 | ++chan->ifstats.tx_dropped; | ||
| 3645 | printk(KERN_INFO "%s: ERROR, Tx intr could not send, dropping %s:\n", | ||
| 3646 | card->devname,dev->name); | ||
| 3647 | ++chan->if_send_stat.if_send_bfr_not_passed_to_adptr; | ||
| 3648 | return 0; | ||
| 3649 | } | ||
| 3650 | } | ||
| 3651 | |||
| 3652 | if (chan->common.usedby == API){ | ||
| 3653 | /* Remove the API Header */ | ||
| 3654 | x25api_hdr_t *api_data = (x25api_hdr_t *)buff; | ||
| 3655 | |||
| 3656 | /* Set the qdm bits from the packet header | ||
| 3657 | * User has the option to set the qdm bits | ||
| 3658 | */ | ||
| 3659 | qdm = api_data->qdm; | ||
| 3660 | |||
| 3661 | orig_len = len = data_len - sizeof(x25api_hdr_t); | ||
| 3662 | data = (unsigned char*)buff + sizeof(x25api_hdr_t); | ||
| 3663 | }else{ | ||
| 3664 | data = buff; | ||
| 3665 | orig_len = len = data_len; | ||
| 3666 | } | ||
| 3667 | |||
| 3668 | if (tx_intr){ | ||
| 3669 | /* We are in tx_intr, minus the tx_offset from | ||
| 3670 | * the total length. The tx_offset part of the | ||
| 3671 | * data has already been sent. Also, move the | ||
| 3672 | * data pointer to proper offset location. | ||
| 3673 | */ | ||
| 3674 | len -= chan->tx_offset; | ||
| 3675 | data = (unsigned char*)data + chan->tx_offset; | ||
| 3676 | } | ||
| 3677 | |||
| 3678 | /* Check if the packet length is greater than MTU | ||
| 3679 | * If YES: Cut the len to MTU and set the M bit | ||
| 3680 | */ | ||
| 3681 | if (len > chan->tx_pkt_size && !card->u.x.LAPB_hdlc){ | ||
| 3682 | len = chan->tx_pkt_size; | ||
| 3683 | qdm |= M_BIT; | ||
| 3684 | } | ||
| 3685 | |||
| 3686 | |||
| 3687 | /* Pass only first three bits of the qdm byte to the send | ||
| 3688 | * routine. In case user sets any other bit which might | ||
| 3689 | * cause errors. | ||
| 3690 | */ | ||
| 3691 | |||
| 3692 | switch(x25_send(card, chan->common.lcn, (qdm&0x07), len, data)){ | ||
| 3693 | case 0x00: /* success */ | ||
| 3694 | chan->i_timeout_sofar = jiffies; | ||
| 3695 | |||
| 3696 | dev->trans_start=jiffies; | ||
| 3697 | |||
| 3698 | if ((qdm & M_BIT) && !card->u.x.LAPB_hdlc){ | ||
| 3699 | if (!tx_intr){ | ||
| 3700 | /* The M bit was set, which means that part of the | ||
| 3701 | * packet has been sent. Copy the packet into a buffer | ||
| 3702 | * and set the offset to len, so on next tx_inter | ||
| 3703 | * the packet will be sent using the below offset. | ||
| 3704 | */ | ||
| 3705 | chan->tx_offset += len; | ||
| 3706 | |||
| 3707 | ++chan->ifstats.tx_packets; | ||
| 3708 | chan->ifstats.tx_bytes += len; | ||
| 3709 | |||
| 3710 | if (chan->tx_offset < orig_len){ | ||
| 3711 | setup_for_delayed_transmit (dev, buff, data_len); | ||
| 3712 | } | ||
| 3713 | res=0; | ||
| 3714 | }else{ | ||
| 3715 | /* We are already in tx_inter, thus data is already | ||
| 3716 | * in the buffer. Update the offset and wait for | ||
| 3717 | * next tx_intr. We add on to the offset, since data can | ||
| 3718 | * be X number of times larger than max data size. | ||
| 3719 | */ | ||
| 3720 | ++chan->ifstats.tx_packets; | ||
| 3721 | chan->ifstats.tx_bytes += len; | ||
| 3722 | |||
| 3723 | ++chan->if_send_stat.if_send_bfr_passed_to_adptr; | ||
| 3724 | chan->tx_offset += len; | ||
| 3725 | |||
| 3726 | /* The user can set the qdm bit as well. | ||
| 3727 | * If the entire packet was sent and qdm is still | ||
| 3728 | * set, than it's the user who has set the M bit. In that, | ||
| 3729 | * case indicate that the packet was send by returning | ||
| 3730 | * 0 and wait for a new packet. Otherwise, wait for next | ||
| 3731 | * tx interrupt to send the rest of the packet */ | ||
| 3732 | |||
| 3733 | if (chan->tx_offset < orig_len){ | ||
| 3734 | res=1; | ||
| 3735 | }else{ | ||
| 3736 | res=0; | ||
| 3737 | } | ||
| 3738 | } | ||
| 3739 | }else{ | ||
| 3740 | ++chan->ifstats.tx_packets; | ||
| 3741 | chan->ifstats.tx_bytes += len; | ||
| 3742 | ++chan->if_send_stat.if_send_bfr_passed_to_adptr; | ||
| 3743 | res=0; | ||
| 3744 | } | ||
| 3745 | break; | ||
| 3746 | |||
| 3747 | case 0x33: /* Tx busy */ | ||
| 3748 | if (tx_intr){ | ||
| 3749 | printk(KERN_INFO "%s: Tx_intr: Big Error dropping packet %s\n", | ||
| 3750 | card->devname,dev->name); | ||
| 3751 | ++chan->ifstats.tx_dropped; | ||
| 3752 | ++card->wandev.stats.tx_dropped; | ||
| 3753 | ++chan->if_send_stat.if_send_bfr_not_passed_to_adptr; | ||
| 3754 | res=0; | ||
| 3755 | }else{ | ||
| 3756 | DBG_PRINTK(KERN_INFO | ||
| 3757 | "%s: Send: Big Error should have tx: storring %s\n", | ||
| 3758 | card->devname,dev->name); | ||
| 3759 | setup_for_delayed_transmit (dev, buff, data_len); | ||
| 3760 | res=1; | ||
| 3761 | } | ||
| 3762 | break; | ||
| 3763 | |||
| 3764 | default: /* failure */ | ||
| 3765 | ++chan->ifstats.tx_errors; | ||
| 3766 | if (tx_intr){ | ||
| 3767 | printk(KERN_INFO "%s: Tx_intr: Failure to send, dropping %s\n", | ||
| 3768 | card->devname,dev->name); | ||
| 3769 | ++chan->ifstats.tx_dropped; | ||
| 3770 | ++card->wandev.stats.tx_dropped; | ||
| 3771 | ++chan->if_send_stat.if_send_bfr_not_passed_to_adptr; | ||
| 3772 | res=0; | ||
| 3773 | }else{ | ||
| 3774 | DBG_PRINTK(KERN_INFO "%s: Send: Failure to send !!!, storing %s\n", | ||
| 3775 | card->devname,dev->name); | ||
| 3776 | setup_for_delayed_transmit (dev, buff, data_len); | ||
| 3777 | res=1; | ||
| 3778 | } | ||
| 3779 | break; | ||
| 3780 | } | ||
| 3781 | return res; | ||
| 3782 | } | ||
| 3783 | |||
| 3784 | |||
| 3785 | /* | ||
| 3786 | * Parse X.25 call request data and fill x25_call_info_t structure. | ||
| 3787 | */ | ||
| 3788 | |||
| 3789 | static void parse_call_info (unsigned char* str, x25_call_info_t* info) | ||
| 3790 | { | ||
| 3791 | memset(info, 0, sizeof(x25_call_info_t)); | ||
| 3792 | for (; *str; ++str) | ||
| 3793 | { | ||
| 3794 | int i; | ||
| 3795 | unsigned char ch; | ||
| 3796 | |||
| 3797 | if (*str == '-') switch (str[1]) { | ||
| 3798 | |||
| 3799 | /* Take minus 2 off the maximum size so that | ||
| 3800 | * last byte is 0. This way we can use string | ||
| 3801 | * manipulaton functions on call information. | ||
| 3802 | */ | ||
| 3803 | |||
| 3804 | case 'd': /* destination address */ | ||
| 3805 | for (i = 0; i < (MAX_X25_ADDR_SIZE-2); ++i){ | ||
| 3806 | ch = str[2+i]; | ||
| 3807 | if (isspace(ch)) break; | ||
| 3808 | info->dest[i] = ch; | ||
| 3809 | } | ||
| 3810 | break; | ||
| 3811 | |||
| 3812 | case 's': /* source address */ | ||
| 3813 | for (i = 0; i < (MAX_X25_ADDR_SIZE-2); ++i){ | ||
| 3814 | ch = str[2+i]; | ||
| 3815 | if (isspace(ch)) break; | ||
| 3816 | info->src[i] = ch; | ||
| 3817 | } | ||
| 3818 | break; | ||
| 3819 | |||
| 3820 | case 'u': /* user data */ | ||
| 3821 | for (i = 0; i < (MAX_X25_DATA_SIZE-2); ++i){ | ||
| 3822 | ch = str[2+i]; | ||
| 3823 | if (isspace(ch)) break; | ||
| 3824 | info->user[i] = ch; | ||
| 3825 | } | ||
| 3826 | info->nuser = i; | ||
| 3827 | break; | ||
| 3828 | |||
| 3829 | case 'f': /* facilities */ | ||
| 3830 | for (i = 0; i < (MAX_X25_FACL_SIZE-2); ++i){ | ||
| 3831 | ch = str[2+i]; | ||
| 3832 | if (isspace(ch)) break; | ||
| 3833 | info->facil[i] = ch; | ||
| 3834 | } | ||
| 3835 | info->nfacil = i; | ||
| 3836 | break; | ||
| 3837 | } | ||
| 3838 | } | ||
| 3839 | } | ||
| 3840 | |||
| 3841 | /* | ||
| 3842 | * Convert line speed in bps to a number used by S502 code. | ||
| 3843 | */ | ||
| 3844 | |||
| 3845 | static unsigned char bps_to_speed_code (unsigned long bps) | ||
| 3846 | { | ||
| 3847 | unsigned char number; | ||
| 3848 | |||
| 3849 | if (bps <= 1200) number = 0x01; | ||
| 3850 | else if (bps <= 2400) number = 0x02; | ||
| 3851 | else if (bps <= 4800) number = 0x03; | ||
| 3852 | else if (bps <= 9600) number = 0x04; | ||
| 3853 | else if (bps <= 19200) number = 0x05; | ||
| 3854 | else if (bps <= 38400) number = 0x06; | ||
| 3855 | else if (bps <= 45000) number = 0x07; | ||
| 3856 | else if (bps <= 56000) number = 0x08; | ||
| 3857 | else if (bps <= 64000) number = 0x09; | ||
| 3858 | else if (bps <= 74000) number = 0x0A; | ||
| 3859 | else if (bps <= 112000) number = 0x0B; | ||
| 3860 | else if (bps <= 128000) number = 0x0C; | ||
| 3861 | else number = 0x0D; | ||
| 3862 | |||
| 3863 | return number; | ||
| 3864 | } | ||
| 3865 | |||
| 3866 | /* | ||
| 3867 | * Convert decimal string to unsigned integer. | ||
| 3868 | * If len != 0 then only 'len' characters of the string are converted. | ||
| 3869 | */ | ||
| 3870 | |||
| 3871 | static unsigned int dec_to_uint (unsigned char* str, int len) | ||
| 3872 | { | ||
| 3873 | unsigned val; | ||
| 3874 | |||
| 3875 | if (!len) | ||
| 3876 | len = strlen(str); | ||
| 3877 | |||
| 3878 | for (val = 0; len && isdigit(*str); ++str, --len) | ||
| 3879 | val = (val * 10) + (*str - (unsigned)'0'); | ||
| 3880 | |||
| 3881 | return val; | ||
| 3882 | } | ||
| 3883 | |||
| 3884 | /* | ||
| 3885 | * Convert hex string to unsigned integer. | ||
| 3886 | * If len != 0 then only 'len' characters of the string are conferted. | ||
| 3887 | */ | ||
| 3888 | |||
| 3889 | static unsigned int hex_to_uint (unsigned char* str, int len) | ||
| 3890 | { | ||
| 3891 | unsigned val, ch; | ||
| 3892 | |||
| 3893 | if (!len) | ||
| 3894 | len = strlen(str); | ||
| 3895 | |||
| 3896 | for (val = 0; len; ++str, --len) | ||
| 3897 | { | ||
| 3898 | ch = *str; | ||
| 3899 | if (isdigit(ch)) | ||
| 3900 | val = (val << 4) + (ch - (unsigned)'0'); | ||
| 3901 | else if (isxdigit(ch)) | ||
| 3902 | val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10); | ||
| 3903 | else break; | ||
| 3904 | } | ||
| 3905 | return val; | ||
| 3906 | } | ||
| 3907 | |||
| 3908 | |||
| 3909 | static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto) | ||
| 3910 | { | ||
| 3911 | int i; | ||
| 3912 | |||
| 3913 | if( proto == ETH_P_IPX) { | ||
| 3914 | /* It's an IPX packet */ | ||
| 3915 | if(!enable_IPX) { | ||
| 3916 | /* Return 1 so we don't pass it up the stack. */ | ||
| 3917 | return 1; | ||
| 3918 | } | ||
| 3919 | } else { | ||
| 3920 | /* It's not IPX so pass it up the stack.*/ | ||
| 3921 | return 0; | ||
| 3922 | } | ||
| 3923 | |||
| 3924 | if( sendpacket[16] == 0x90 && | ||
| 3925 | sendpacket[17] == 0x04) | ||
| 3926 | { | ||
| 3927 | /* It's IPXWAN */ | ||
| 3928 | |||
| 3929 | if( sendpacket[2] == 0x02 && | ||
| 3930 | sendpacket[34] == 0x00) | ||
| 3931 | { | ||
| 3932 | /* It's a timer request packet */ | ||
| 3933 | printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); | ||
| 3934 | |||
| 3935 | /* Go through the routing options and answer no to every | ||
| 3936 | * option except Unnumbered RIP/SAP | ||
| 3937 | */ | ||
| 3938 | for(i = 41; sendpacket[i] == 0x00; i += 5) | ||
| 3939 | { | ||
| 3940 | /* 0x02 is the option for Unnumbered RIP/SAP */ | ||
| 3941 | if( sendpacket[i + 4] != 0x02) | ||
| 3942 | { | ||
| 3943 | sendpacket[i + 1] = 0; | ||
| 3944 | } | ||
| 3945 | } | ||
| 3946 | |||
| 3947 | /* Skip over the extended Node ID option */ | ||
| 3948 | if( sendpacket[i] == 0x04 ) | ||
| 3949 | { | ||
| 3950 | i += 8; | ||
| 3951 | } | ||
| 3952 | |||
| 3953 | /* We also want to turn off all header compression opt. */ | ||
| 3954 | for(; sendpacket[i] == 0x80 ;) | ||
| 3955 | { | ||
| 3956 | sendpacket[i + 1] = 0; | ||
| 3957 | i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; | ||
| 3958 | } | ||
| 3959 | |||
| 3960 | /* Set the packet type to timer response */ | ||
| 3961 | sendpacket[34] = 0x01; | ||
| 3962 | |||
| 3963 | printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname); | ||
| 3964 | } | ||
| 3965 | else if( sendpacket[34] == 0x02 ) | ||
| 3966 | { | ||
| 3967 | /* This is an information request packet */ | ||
| 3968 | printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname); | ||
| 3969 | |||
| 3970 | /* Set the packet type to information response */ | ||
| 3971 | sendpacket[34] = 0x03; | ||
| 3972 | |||
| 3973 | /* Set the router name */ | ||
| 3974 | sendpacket[51] = 'X'; | ||
| 3975 | sendpacket[52] = 'T'; | ||
| 3976 | sendpacket[53] = 'P'; | ||
| 3977 | sendpacket[54] = 'I'; | ||
| 3978 | sendpacket[55] = 'P'; | ||
| 3979 | sendpacket[56] = 'E'; | ||
| 3980 | sendpacket[57] = '-'; | ||
| 3981 | sendpacket[58] = CVHexToAscii(network_number >> 28); | ||
| 3982 | sendpacket[59] = CVHexToAscii((network_number & 0x0F000000)>> 24); | ||
| 3983 | sendpacket[60] = CVHexToAscii((network_number & 0x00F00000)>> 20); | ||
| 3984 | sendpacket[61] = CVHexToAscii((network_number & 0x000F0000)>> 16); | ||
| 3985 | sendpacket[62] = CVHexToAscii((network_number & 0x0000F000)>> 12); | ||
| 3986 | sendpacket[63] = CVHexToAscii((network_number & 0x00000F00)>> 8); | ||
| 3987 | sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4); | ||
| 3988 | sendpacket[65] = CVHexToAscii(network_number & 0x0000000F); | ||
| 3989 | for(i = 66; i < 99; i+= 1) | ||
| 3990 | { | ||
| 3991 | sendpacket[i] = 0; | ||
| 3992 | } | ||
| 3993 | |||
| 3994 | printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); | ||
| 3995 | } | ||
| 3996 | else | ||
| 3997 | { | ||
| 3998 | printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); | ||
| 3999 | return 0; | ||
| 4000 | } | ||
| 4001 | |||
| 4002 | /* Set the WNodeID to our network address */ | ||
| 4003 | sendpacket[35] = (unsigned char)(network_number >> 24); | ||
| 4004 | sendpacket[36] = (unsigned char)((network_number & 0x00FF0000) >> 16); | ||
| 4005 | sendpacket[37] = (unsigned char)((network_number & 0x0000FF00) >> 8); | ||
| 4006 | sendpacket[38] = (unsigned char)(network_number & 0x000000FF); | ||
| 4007 | |||
| 4008 | return 1; | ||
| 4009 | } else { | ||
| 4010 | /*If we get here it's an IPX-data packet, so it'll get passed up the stack. | ||
| 4011 | */ | ||
| 4012 | /* switch the network numbers */ | ||
| 4013 | switch_net_numbers(sendpacket, network_number, 1); | ||
| 4014 | return 0; | ||
| 4015 | } | ||
| 4016 | } | ||
| 4017 | |||
| 4018 | /* | ||
| 4019 | * If incoming is 0 (outgoing)- if the net numbers is ours make it 0 | ||
| 4020 | * if incoming is 1 - if the net number is 0 make it ours | ||
| 4021 | */ | ||
| 4022 | |||
| 4023 | static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) | ||
| 4024 | { | ||
| 4025 | unsigned long pnetwork_number; | ||
| 4026 | |||
| 4027 | pnetwork_number = (unsigned long)((sendpacket[6] << 24) + | ||
| 4028 | (sendpacket[7] << 16) + (sendpacket[8] << 8) + | ||
| 4029 | sendpacket[9]); | ||
| 4030 | |||
| 4031 | |||
| 4032 | if (!incoming) { | ||
| 4033 | /*If the destination network number is ours, make it 0 */ | ||
| 4034 | if( pnetwork_number == network_number) { | ||
| 4035 | sendpacket[6] = sendpacket[7] = sendpacket[8] = | ||
| 4036 | sendpacket[9] = 0x00; | ||
| 4037 | } | ||
| 4038 | } else { | ||
| 4039 | /* If the incoming network is 0, make it ours */ | ||
| 4040 | if( pnetwork_number == 0) { | ||
| 4041 | sendpacket[6] = (unsigned char)(network_number >> 24); | ||
| 4042 | sendpacket[7] = (unsigned char)((network_number & | ||
| 4043 | 0x00FF0000) >> 16); | ||
| 4044 | sendpacket[8] = (unsigned char)((network_number & | ||
| 4045 | 0x0000FF00) >> 8); | ||
| 4046 | sendpacket[9] = (unsigned char)(network_number & | ||
| 4047 | 0x000000FF); | ||
| 4048 | } | ||
| 4049 | } | ||
| 4050 | |||
| 4051 | |||
| 4052 | pnetwork_number = (unsigned long)((sendpacket[18] << 24) + | ||
| 4053 | (sendpacket[19] << 16) + (sendpacket[20] << 8) + | ||
| 4054 | sendpacket[21]); | ||
| 4055 | |||
| 4056 | |||
| 4057 | if( !incoming ) { | ||
| 4058 | /* If the source network is ours, make it 0 */ | ||
| 4059 | if( pnetwork_number == network_number) { | ||
| 4060 | sendpacket[18] = sendpacket[19] = sendpacket[20] = | ||
| 4061 | sendpacket[21] = 0x00; | ||
| 4062 | } | ||
| 4063 | } else { | ||
| 4064 | /* If the source network is 0, make it ours */ | ||
| 4065 | if( pnetwork_number == 0 ) { | ||
| 4066 | sendpacket[18] = (unsigned char)(network_number >> 24); | ||
| 4067 | sendpacket[19] = (unsigned char)((network_number & | ||
| 4068 | 0x00FF0000) >> 16); | ||
| 4069 | sendpacket[20] = (unsigned char)((network_number & | ||
| 4070 | 0x0000FF00) >> 8); | ||
| 4071 | sendpacket[21] = (unsigned char)(network_number & | ||
| 4072 | 0x000000FF); | ||
| 4073 | } | ||
| 4074 | } | ||
| 4075 | } /* switch_net_numbers */ | ||
| 4076 | |||
| 4077 | |||
| 4078 | |||
| 4079 | |||
| 4080 | /********************* X25API SPECIFIC FUNCTIONS ****************/ | ||
| 4081 | |||
| 4082 | |||
| 4083 | /*=============================================================== | ||
| 4084 | * find_channel | ||
| 4085 | * | ||
| 4086 | * Manages the lcn to device map. It increases performance | ||
| 4087 | * because it eliminates the need to search through the link | ||
| 4088 | * list for a device which is bounded to a specific lcn. | ||
| 4089 | * | ||
| 4090 | *===============================================================*/ | ||
| 4091 | |||
| 4092 | |||
| 4093 | struct net_device *find_channel(sdla_t *card, unsigned lcn) | ||
| 4094 | { | ||
| 4095 | if (card->u.x.LAPB_hdlc){ | ||
| 4096 | |||
| 4097 | return card->wandev.dev; | ||
| 4098 | |||
| 4099 | }else{ | ||
| 4100 | /* We don't know whether the incoming lcn | ||
| 4101 | * is a PVC or an SVC channel. But we do know that | ||
| 4102 | * the lcn cannot be for both the PVC and the SVC | ||
| 4103 | * channel. | ||
| 4104 | |||
| 4105 | * If the lcn number is greater or equal to 255, | ||
| 4106 | * take the modulo 255 of that number. We only have | ||
| 4107 | * 255 locations, thus higher numbers must be mapped | ||
| 4108 | * to a number between 0 and 245. | ||
| 4109 | |||
| 4110 | * We must separate pvc's and svc's since two don't | ||
| 4111 | * have to be contiguous. Meaning pvc's can start | ||
| 4112 | * from 1 to 10 and svc's can start from 256 to 266. | ||
| 4113 | * But 256%255 is 1, i.e. CONFLICT. | ||
| 4114 | */ | ||
| 4115 | |||
| 4116 | |||
| 4117 | /* Highest LCN number must be less or equal to 4096 */ | ||
| 4118 | if ((lcn <= MAX_LCN_NUM) && (lcn > 0)){ | ||
| 4119 | |||
| 4120 | if (lcn < X25_MAX_CHAN){ | ||
| 4121 | if (card->u.x.svc_to_dev_map[lcn]) | ||
| 4122 | return card->u.x.svc_to_dev_map[lcn]; | ||
| 4123 | |||
| 4124 | if (card->u.x.pvc_to_dev_map[lcn]) | ||
| 4125 | return card->u.x.pvc_to_dev_map[lcn]; | ||
| 4126 | |||
| 4127 | }else{ | ||
| 4128 | int new_lcn = lcn%X25_MAX_CHAN; | ||
| 4129 | if (card->u.x.svc_to_dev_map[new_lcn]) | ||
| 4130 | return card->u.x.svc_to_dev_map[new_lcn]; | ||
| 4131 | |||
| 4132 | if (card->u.x.pvc_to_dev_map[new_lcn]) | ||
| 4133 | return card->u.x.pvc_to_dev_map[new_lcn]; | ||
| 4134 | } | ||
| 4135 | } | ||
| 4136 | return NULL; | ||
| 4137 | } | ||
| 4138 | } | ||
| 4139 | |||
| 4140 | void bind_lcn_to_dev(sdla_t *card, struct net_device *dev, unsigned lcn) | ||
| 4141 | { | ||
| 4142 | x25_channel_t *chan = dev->priv; | ||
| 4143 | |||
| 4144 | /* Modulo the lcn number by X25_MAX_CHAN (255) | ||
| 4145 | * because the lcn number can be greater than 255 | ||
| 4146 | * | ||
| 4147 | * We need to split svc and pvc since they don't have | ||
| 4148 | * to be contigous. | ||
| 4149 | */ | ||
| 4150 | |||
| 4151 | if (chan->common.svc){ | ||
| 4152 | card->u.x.svc_to_dev_map[(lcn % X25_MAX_CHAN)] = dev; | ||
| 4153 | }else{ | ||
| 4154 | card->u.x.pvc_to_dev_map[(lcn % X25_MAX_CHAN)] = dev; | ||
| 4155 | } | ||
| 4156 | chan->common.lcn = lcn; | ||
| 4157 | } | ||
| 4158 | |||
| 4159 | |||
| 4160 | |||
| 4161 | /*=============================================================== | ||
| 4162 | * x25api_bh | ||
| 4163 | * | ||
| 4164 | * | ||
| 4165 | *==============================================================*/ | ||
| 4166 | |||
| 4167 | static void x25api_bh(struct net_device* dev) | ||
| 4168 | { | ||
| 4169 | x25_channel_t* chan = dev->priv; | ||
| 4170 | sdla_t* card = chan->card; | ||
| 4171 | struct sk_buff *skb; | ||
| 4172 | |||
| 4173 | if (atomic_read(&chan->bh_buff_used) == 0){ | ||
| 4174 | printk(KERN_INFO "%s: BH Buffer Empty in BH\n", | ||
| 4175 | card->devname); | ||
| 4176 | clear_bit(0, &chan->tq_working); | ||
| 4177 | return; | ||
| 4178 | } | ||
| 4179 | |||
| 4180 | while (atomic_read(&chan->bh_buff_used)){ | ||
| 4181 | |||
| 4182 | /* If the sock is in the process of unlinking the | ||
| 4183 | * driver from the socket, we must get out. | ||
| 4184 | * This never happends but is a sanity check. */ | ||
| 4185 | if (test_bit(0,&chan->common.common_critical)){ | ||
| 4186 | clear_bit(0, &chan->tq_working); | ||
| 4187 | return; | ||
| 4188 | } | ||
| 4189 | |||
| 4190 | /* If LAPB HDLC, do not drop packets if socket is | ||
| 4191 | * not connected. Let the buffer fill up and | ||
| 4192 | * turn off rx interrupt */ | ||
| 4193 | if (card->u.x.LAPB_hdlc){ | ||
| 4194 | if (chan->common.sk == NULL || chan->common.func == NULL){ | ||
| 4195 | clear_bit(0, &chan->tq_working); | ||
| 4196 | return; | ||
| 4197 | } | ||
| 4198 | } | ||
| 4199 | |||
| 4200 | skb = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb; | ||
| 4201 | |||
| 4202 | if (skb == NULL){ | ||
| 4203 | printk(KERN_INFO "%s: BH Skb empty for read %i\n", | ||
| 4204 | card->devname,chan->bh_read); | ||
| 4205 | }else{ | ||
| 4206 | |||
| 4207 | if (chan->common.sk == NULL || chan->common.func == NULL){ | ||
| 4208 | printk(KERN_INFO "%s: BH: Socket disconnected, dropping\n", | ||
| 4209 | card->devname); | ||
| 4210 | dev_kfree_skb_any(skb); | ||
| 4211 | x25api_bh_cleanup(dev); | ||
| 4212 | ++chan->ifstats.rx_dropped; | ||
| 4213 | ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; | ||
| 4214 | continue; | ||
| 4215 | } | ||
| 4216 | |||
| 4217 | |||
| 4218 | if (chan->common.func(skb,dev,chan->common.sk) != 0){ | ||
| 4219 | /* Sock full cannot send, queue us for another | ||
| 4220 | * try | ||
| 4221 | */ | ||
| 4222 | printk(KERN_INFO "%s: BH: !!! Packet failed to send !!!!! \n", | ||
| 4223 | card->devname); | ||
| 4224 | atomic_set(&chan->common.receive_block,1); | ||
| 4225 | return; | ||
| 4226 | }else{ | ||
| 4227 | x25api_bh_cleanup(dev); | ||
| 4228 | ++chan->rx_intr_stat.rx_intr_bfr_passed_to_stack; | ||
| 4229 | } | ||
| 4230 | } | ||
| 4231 | } | ||
| 4232 | clear_bit(0, &chan->tq_working); | ||
| 4233 | |||
| 4234 | return; | ||
| 4235 | } | ||
| 4236 | |||
| 4237 | /*=============================================================== | ||
| 4238 | * x25api_bh_cleanup | ||
| 4239 | * | ||
| 4240 | * | ||
| 4241 | *==============================================================*/ | ||
| 4242 | |||
| 4243 | static int x25api_bh_cleanup(struct net_device *dev) | ||
| 4244 | { | ||
| 4245 | x25_channel_t* chan = dev->priv; | ||
| 4246 | sdla_t *card = chan->card; | ||
| 4247 | TX25Status* status = card->flags; | ||
| 4248 | |||
| 4249 | |||
| 4250 | ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL; | ||
| 4251 | |||
| 4252 | if (chan->bh_read == MAX_BH_BUFF){ | ||
| 4253 | chan->bh_read=0; | ||
| 4254 | }else{ | ||
| 4255 | ++chan->bh_read; | ||
| 4256 | } | ||
| 4257 | |||
| 4258 | /* If the Receive interrupt was off, it means | ||
| 4259 | * that we filled up our circular buffer. Check | ||
| 4260 | * that we have space in the buffer. If so | ||
| 4261 | * turn the RX interrupt back on. | ||
| 4262 | */ | ||
| 4263 | if (!(status->imask & INTR_ON_RX_FRAME)){ | ||
| 4264 | if (atomic_read(&chan->bh_buff_used) < (MAX_BH_BUFF+1)){ | ||
| 4265 | printk(KERN_INFO "%s: BH: Turning on the interrupt\n", | ||
| 4266 | card->devname); | ||
| 4267 | status->imask |= INTR_ON_RX_FRAME; | ||
| 4268 | } | ||
| 4269 | } | ||
| 4270 | |||
| 4271 | atomic_dec(&chan->bh_buff_used); | ||
| 4272 | return 0; | ||
| 4273 | } | ||
| 4274 | |||
| 4275 | |||
| 4276 | /*=============================================================== | ||
| 4277 | * bh_enqueue | ||
| 4278 | * | ||
| 4279 | * | ||
| 4280 | *==============================================================*/ | ||
| 4281 | |||
| 4282 | static int bh_enqueue(struct net_device *dev, struct sk_buff *skb) | ||
| 4283 | { | ||
| 4284 | x25_channel_t* chan = dev->priv; | ||
| 4285 | sdla_t *card = chan->card; | ||
| 4286 | TX25Status* status = card->flags; | ||
| 4287 | |||
| 4288 | if (atomic_read(&chan->bh_buff_used) == (MAX_BH_BUFF+1)){ | ||
| 4289 | printk(KERN_INFO "%s: Bottom half buffer FULL\n", | ||
| 4290 | card->devname); | ||
| 4291 | return 1; | ||
| 4292 | } | ||
| 4293 | |||
| 4294 | ((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb; | ||
| 4295 | |||
| 4296 | if (chan->bh_write == MAX_BH_BUFF){ | ||
| 4297 | chan->bh_write=0; | ||
| 4298 | }else{ | ||
| 4299 | ++chan->bh_write; | ||
| 4300 | } | ||
| 4301 | |||
| 4302 | atomic_inc(&chan->bh_buff_used); | ||
| 4303 | |||
| 4304 | if (atomic_read(&chan->bh_buff_used) == (MAX_BH_BUFF+1)){ | ||
| 4305 | printk(KERN_INFO "%s: Buffer is now full, Turning off RX Intr\n", | ||
| 4306 | card->devname); | ||
| 4307 | status->imask &= ~INTR_ON_RX_FRAME; | ||
| 4308 | } | ||
| 4309 | |||
| 4310 | return 0; | ||
| 4311 | } | ||
| 4312 | |||
| 4313 | |||
| 4314 | /*=============================================================== | ||
| 4315 | * timer_intr_cmd_exec | ||
| 4316 | * | ||
| 4317 | * Called by timer interrupt to execute a command | ||
| 4318 | *===============================================================*/ | ||
| 4319 | |||
| 4320 | static int timer_intr_cmd_exec (sdla_t* card) | ||
| 4321 | { | ||
| 4322 | struct net_device *dev; | ||
| 4323 | unsigned char more_to_exec=0; | ||
| 4324 | volatile x25_channel_t *chan=NULL; | ||
| 4325 | int i=0,bad_cmd=0,err=0; | ||
| 4326 | |||
| 4327 | if (card->u.x.cmd_dev == NULL){ | ||
| 4328 | card->u.x.cmd_dev = card->wandev.dev; | ||
| 4329 | } | ||
| 4330 | |||
| 4331 | dev = card->u.x.cmd_dev; | ||
| 4332 | |||
| 4333 | for (;;){ | ||
| 4334 | |||
| 4335 | chan = dev->priv; | ||
| 4336 | |||
| 4337 | if (atomic_read(&chan->common.command)){ | ||
| 4338 | |||
| 4339 | bad_cmd = check_bad_command(card,dev); | ||
| 4340 | |||
| 4341 | if ((!chan->common.mbox || atomic_read(&chan->common.disconnect)) && | ||
| 4342 | !bad_cmd){ | ||
| 4343 | |||
| 4344 | /* Socket has died or exited, We must bring the | ||
| 4345 | * channel down before anybody else tries to | ||
| 4346 | * use it */ | ||
| 4347 | err = channel_disconnect(card,dev); | ||
| 4348 | }else{ | ||
| 4349 | err = execute_delayed_cmd(card, dev, | ||
| 4350 | (mbox_cmd_t*)chan->common.mbox, | ||
| 4351 | bad_cmd); | ||
| 4352 | } | ||
| 4353 | |||
| 4354 | switch (err){ | ||
| 4355 | |||
| 4356 | case RETURN_RESULT: | ||
| 4357 | |||
| 4358 | /* Return the result to the socket without | ||
| 4359 | * delay. NO_WAIT Command */ | ||
| 4360 | atomic_set(&chan->common.command,0); | ||
| 4361 | if (atomic_read(&card->u.x.command_busy)) | ||
| 4362 | atomic_set(&card->u.x.command_busy,0); | ||
| 4363 | |||
| 4364 | send_delayed_cmd_result(card,dev,card->mbox); | ||
| 4365 | |||
| 4366 | more_to_exec=0; | ||
| 4367 | break; | ||
| 4368 | case DELAY_RESULT: | ||
| 4369 | |||
| 4370 | /* Wait for the remote to respond, before | ||
| 4371 | * sending the result up to the socket. | ||
| 4372 | * WAIT command */ | ||
| 4373 | if (atomic_read(&card->u.x.command_busy)) | ||
| 4374 | atomic_set(&card->u.x.command_busy,0); | ||
| 4375 | |||
| 4376 | atomic_set(&chan->common.command,0); | ||
| 4377 | more_to_exec=0; | ||
| 4378 | break; | ||
| 4379 | default: | ||
| 4380 | |||
| 4381 | /* If command could not be executed for | ||
| 4382 | * some reason (i.e return code 0x33 busy) | ||
| 4383 | * set the more_to_exec bit which will | ||
| 4384 | * indicate that this command must be exectued | ||
| 4385 | * again during next timer interrupt | ||
| 4386 | */ | ||
| 4387 | more_to_exec=1; | ||
| 4388 | if (atomic_read(&card->u.x.command_busy) == 0) | ||
| 4389 | atomic_set(&card->u.x.command_busy,1); | ||
| 4390 | break; | ||
| 4391 | } | ||
| 4392 | |||
| 4393 | bad_cmd=0; | ||
| 4394 | |||
| 4395 | /* If flags is set, there are no hdlc buffers, | ||
| 4396 | * thus, wait for the next pass and try the | ||
| 4397 | * same command again. Otherwise, start searching | ||
| 4398 | * from next device on the next pass. | ||
| 4399 | */ | ||
| 4400 | if (!more_to_exec){ | ||
| 4401 | dev = move_dev_to_next(card,dev); | ||
| 4402 | } | ||
| 4403 | break; | ||
| 4404 | }else{ | ||
| 4405 | /* This device has nothing to execute, | ||
| 4406 | * go to next. | ||
| 4407 | */ | ||
| 4408 | if (atomic_read(&card->u.x.command_busy)) | ||
| 4409 | atomic_set(&card->u.x.command_busy,0); | ||
| 4410 | dev = move_dev_to_next(card,dev); | ||
| 4411 | } | ||
| 4412 | |||
| 4413 | if (++i == card->u.x.no_dev){ | ||
| 4414 | if (!more_to_exec){ | ||
| 4415 | DBG_PRINTK(KERN_INFO "%s: Nothing to execute in Timer\n", | ||
| 4416 | card->devname); | ||
| 4417 | if (atomic_read(&card->u.x.command_busy)){ | ||
| 4418 | atomic_set(&card->u.x.command_busy,0); | ||
| 4419 | } | ||
| 4420 | } | ||
| 4421 | break; | ||
| 4422 | } | ||
| 4423 | |||
| 4424 | } //End of FOR | ||
| 4425 | |||
| 4426 | card->u.x.cmd_dev = dev; | ||
| 4427 | |||
| 4428 | if (more_to_exec){ | ||
| 4429 | /* If more commands are pending, do not turn off timer | ||
| 4430 | * interrupt */ | ||
| 4431 | return 1; | ||
| 4432 | }else{ | ||
| 4433 | /* No more commands, turn off timer interrupt */ | ||
| 4434 | return 0; | ||
| 4435 | } | ||
| 4436 | } | ||
| 4437 | |||
| 4438 | /*=============================================================== | ||
| 4439 | * execute_delayed_cmd | ||
| 4440 | * | ||
| 4441 | * Execute an API command which was passed down from the | ||
| 4442 | * sock. Sock is very limited in which commands it can | ||
| 4443 | * execute. Wait and No Wait commands are supported. | ||
| 4444 | * Place Call, Clear Call and Reset wait commands, where | ||
| 4445 | * Accept Call is a no_wait command. | ||
| 4446 | * | ||
| 4447 | *===============================================================*/ | ||
| 4448 | |||
| 4449 | static int execute_delayed_cmd(sdla_t* card, struct net_device *dev, | ||
| 4450 | mbox_cmd_t *usr_cmd, char bad_cmd) | ||
| 4451 | { | ||
| 4452 | TX25Mbox* mbox = card->mbox; | ||
| 4453 | int err; | ||
| 4454 | x25_channel_t *chan = dev->priv; | ||
| 4455 | int delay=RETURN_RESULT; | ||
| 4456 | |||
| 4457 | if (!(*card->u.x.hdlc_buf_status & 0x40) && !bad_cmd){ | ||
| 4458 | return TRY_CMD_AGAIN; | ||
| 4459 | } | ||
| 4460 | |||
| 4461 | /* This way a command is guaranteed to be executed for | ||
| 4462 | * a specific lcn, the network interface is bound to. */ | ||
| 4463 | usr_cmd->cmd.lcn = chan->common.lcn; | ||
| 4464 | |||
| 4465 | |||
| 4466 | /* If channel is pvc, instead of place call | ||
| 4467 | * run x25_channel configuration. If running LAPB HDLC | ||
| 4468 | * enable communications. | ||
| 4469 | */ | ||
| 4470 | if ((!chan->common.svc) && (usr_cmd->cmd.command == X25_PLACE_CALL)){ | ||
| 4471 | |||
| 4472 | if (card->u.x.LAPB_hdlc){ | ||
| 4473 | DBG_PRINTK(KERN_INFO "LAPB: Connecting\n"); | ||
| 4474 | connect(card); | ||
| 4475 | set_chan_state(dev,WAN_CONNECTING); | ||
| 4476 | return DELAY_RESULT; | ||
| 4477 | }else{ | ||
| 4478 | DBG_PRINTK(KERN_INFO "%s: PVC is CONNECTING\n",card->devname); | ||
| 4479 | if (x25_get_chan_conf(card, chan) == CMD_OK){ | ||
| 4480 | set_chan_state(dev, WAN_CONNECTED); | ||
| 4481 | }else{ | ||
| 4482 | set_chan_state(dev, WAN_DISCONNECTED); | ||
| 4483 | } | ||
| 4484 | return RETURN_RESULT; | ||
| 4485 | } | ||
| 4486 | } | ||
| 4487 | |||
| 4488 | /* Copy the socket mbox command onto the board */ | ||
| 4489 | |||
| 4490 | memcpy(&mbox->cmd, &usr_cmd->cmd, sizeof(TX25Cmd)); | ||
| 4491 | if (usr_cmd->cmd.length){ | ||
| 4492 | memcpy(mbox->data, usr_cmd->data, usr_cmd->cmd.length); | ||
| 4493 | } | ||
| 4494 | |||
| 4495 | /* Check if command is bad. We need to copy the cmd into | ||
| 4496 | * the buffer regardless since we return the, mbox to | ||
| 4497 | * the user */ | ||
| 4498 | if (bad_cmd){ | ||
| 4499 | mbox->cmd.result=0x01; | ||
| 4500 | return RETURN_RESULT; | ||
| 4501 | } | ||
| 4502 | |||
| 4503 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 4504 | |||
| 4505 | if (err != CMD_OK && err != X25RES_NOT_READY) | ||
| 4506 | x25_error(card, err, usr_cmd->cmd.command, usr_cmd->cmd.lcn); | ||
| 4507 | |||
| 4508 | if (mbox->cmd.result == X25RES_NOT_READY){ | ||
| 4509 | return TRY_CMD_AGAIN; | ||
| 4510 | } | ||
| 4511 | |||
| 4512 | switch (mbox->cmd.command){ | ||
| 4513 | |||
| 4514 | case X25_PLACE_CALL: | ||
| 4515 | |||
| 4516 | switch (mbox->cmd.result){ | ||
| 4517 | |||
| 4518 | case CMD_OK: | ||
| 4519 | |||
| 4520 | /* Check if Place call is a wait command or a | ||
| 4521 | * no wait command */ | ||
| 4522 | if (atomic_read(&chan->common.command) & 0x80) | ||
| 4523 | delay=RETURN_RESULT; | ||
| 4524 | else | ||
| 4525 | delay=DELAY_RESULT; | ||
| 4526 | |||
| 4527 | |||
| 4528 | DBG_PRINTK(KERN_INFO "\n%s: PLACE CALL Binding dev %s to lcn %i\n", | ||
| 4529 | card->devname,dev->name, mbox->cmd.lcn); | ||
| 4530 | |||
| 4531 | bind_lcn_to_dev (card, dev, mbox->cmd.lcn); | ||
| 4532 | set_chan_state(dev, WAN_CONNECTING); | ||
| 4533 | break; | ||
| 4534 | |||
| 4535 | |||
| 4536 | default: | ||
| 4537 | delay=RETURN_RESULT; | ||
| 4538 | set_chan_state(dev, WAN_DISCONNECTED); | ||
| 4539 | break; | ||
| 4540 | } | ||
| 4541 | break; | ||
| 4542 | |||
| 4543 | case X25_ACCEPT_CALL: | ||
| 4544 | |||
| 4545 | switch (mbox->cmd.result){ | ||
| 4546 | |||
| 4547 | case CMD_OK: | ||
| 4548 | |||
| 4549 | DBG_PRINTK(KERN_INFO "\n%s: ACCEPT Binding dev %s to lcn %i\n", | ||
| 4550 | card->devname,dev->name,mbox->cmd.lcn); | ||
| 4551 | |||
| 4552 | bind_lcn_to_dev (card, dev, mbox->cmd.lcn); | ||
| 4553 | |||
| 4554 | if (x25_get_chan_conf(card, chan) == CMD_OK){ | ||
| 4555 | |||
| 4556 | set_chan_state(dev, WAN_CONNECTED); | ||
| 4557 | delay=RETURN_RESULT; | ||
| 4558 | |||
| 4559 | }else{ | ||
| 4560 | if (x25_clear_call(card, usr_cmd->cmd.lcn, 0, 0) == CMD_OK){ | ||
| 4561 | /* if clear is successful, wait for clear confirm | ||
| 4562 | */ | ||
| 4563 | delay=DELAY_RESULT; | ||
| 4564 | }else{ | ||
| 4565 | /* Do not change the state here. If we fail | ||
| 4566 | * the accept the return code is send up | ||
| 4567 | *the stack, which will ether retry | ||
| 4568 | * or clear the call | ||
| 4569 | */ | ||
| 4570 | DBG_PRINTK(KERN_INFO | ||
| 4571 | "%s: ACCEPT: STATE MAY BE CURRUPTED 2 !!!!!\n", | ||
| 4572 | card->devname); | ||
| 4573 | delay=RETURN_RESULT; | ||
| 4574 | } | ||
| 4575 | } | ||
| 4576 | break; | ||
| 4577 | |||
| 4578 | |||
| 4579 | case X25RES_ASYNC_PACKET: | ||
| 4580 | delay=TRY_CMD_AGAIN; | ||
| 4581 | break; | ||
| 4582 | |||
| 4583 | default: | ||
| 4584 | DBG_PRINTK(KERN_INFO "%s: ACCEPT FAILED\n",card->devname); | ||
| 4585 | if (x25_clear_call(card, usr_cmd->cmd.lcn, 0, 0) == CMD_OK){ | ||
| 4586 | delay=DELAY_RESULT; | ||
| 4587 | }else{ | ||
| 4588 | /* Do not change the state here. If we fail the accept. The | ||
| 4589 | * return code is send up the stack, which will ether retry | ||
| 4590 | * or clear the call */ | ||
| 4591 | DBG_PRINTK(KERN_INFO | ||
| 4592 | "%s: ACCEPT: STATE MAY BE CORRUPTED 1 !!!!!\n", | ||
| 4593 | card->devname); | ||
| 4594 | delay=RETURN_RESULT; | ||
| 4595 | } | ||
| 4596 | } | ||
| 4597 | break; | ||
| 4598 | |||
| 4599 | case X25_CLEAR_CALL: | ||
| 4600 | |||
| 4601 | switch (mbox->cmd.result){ | ||
| 4602 | |||
| 4603 | case CMD_OK: | ||
| 4604 | DBG_PRINTK(KERN_INFO | ||
| 4605 | "CALL CLEAR OK: Dev %s Mbox Lcn %i Chan Lcn %i\n", | ||
| 4606 | dev->name,mbox->cmd.lcn,chan->common.lcn); | ||
| 4607 | set_chan_state(dev, WAN_DISCONNECTING); | ||
| 4608 | delay = DELAY_RESULT; | ||
| 4609 | break; | ||
| 4610 | |||
| 4611 | case X25RES_CHANNEL_IN_USE: | ||
| 4612 | case X25RES_ASYNC_PACKET: | ||
| 4613 | delay = TRY_CMD_AGAIN; | ||
| 4614 | break; | ||
| 4615 | |||
| 4616 | case X25RES_LINK_NOT_IN_ABM: | ||
| 4617 | case X25RES_INVAL_LCN: | ||
| 4618 | case X25RES_INVAL_STATE: | ||
| 4619 | set_chan_state(dev, WAN_DISCONNECTED); | ||
| 4620 | delay = RETURN_RESULT; | ||
| 4621 | break; | ||
| 4622 | |||
| 4623 | default: | ||
| 4624 | /* If command did not execute because of user | ||
| 4625 | * fault, do not change the state. This will | ||
| 4626 | * signal the socket that clear command failed. | ||
| 4627 | * User can retry or close the socket. | ||
| 4628 | * When socket gets killed, it will set the | ||
| 4629 | * chan->disconnect which will signal | ||
| 4630 | * driver to clear the call */ | ||
| 4631 | printk(KERN_INFO "%s: Clear Command Failed, Rc %x\n", | ||
| 4632 | card->devname,mbox->cmd.command); | ||
| 4633 | delay = RETURN_RESULT; | ||
| 4634 | } | ||
| 4635 | break; | ||
| 4636 | } | ||
| 4637 | |||
| 4638 | return delay; | ||
| 4639 | } | ||
| 4640 | |||
| 4641 | /*=============================================================== | ||
| 4642 | * api_incoming_call | ||
| 4643 | * | ||
| 4644 | * Pass an incoming call request up the listening | ||
| 4645 | * sock. If the API sock is not listening reject the | ||
| 4646 | * call. | ||
| 4647 | * | ||
| 4648 | *===============================================================*/ | ||
| 4649 | |||
| 4650 | static int api_incoming_call (sdla_t* card, TX25Mbox *mbox, int lcn) | ||
| 4651 | { | ||
| 4652 | struct sk_buff *skb; | ||
| 4653 | int len = sizeof(TX25Cmd)+mbox->cmd.length; | ||
| 4654 | |||
| 4655 | if (alloc_and_init_skb_buf(card, &skb, len)){ | ||
| 4656 | printk(KERN_INFO "%s: API incoming call, no memory\n",card->devname); | ||
| 4657 | return 1; | ||
| 4658 | } | ||
| 4659 | |||
| 4660 | memcpy(skb_put(skb,len),&mbox->cmd,len); | ||
| 4661 | |||
| 4662 | skb->mac.raw = skb->data; | ||
| 4663 | skb->protocol = htons(X25_PROT); | ||
| 4664 | skb->pkt_type = WAN_PACKET_ASYNC; | ||
| 4665 | |||
| 4666 | if (card->func(skb,card->sk) < 0){ | ||
| 4667 | printk(KERN_INFO "%s: MAJOR ERROR: Failed to send up place call \n",card->devname); | ||
| 4668 | dev_kfree_skb_any(skb); | ||
| 4669 | return 1; | ||
| 4670 | } | ||
| 4671 | |||
| 4672 | return 0; | ||
| 4673 | } | ||
| 4674 | |||
| 4675 | /*=============================================================== | ||
| 4676 | * send_delayed_cmd_result | ||
| 4677 | * | ||
| 4678 | * Wait commands like PLEACE CALL or CLEAR CALL must wait | ||
| 4679 | * until the result arrives. This function passes | ||
| 4680 | * the result to a waiting sock. | ||
| 4681 | * | ||
| 4682 | *===============================================================*/ | ||
| 4683 | static void send_delayed_cmd_result(sdla_t *card, struct net_device *dev, | ||
| 4684 | TX25Mbox* mbox) | ||
| 4685 | { | ||
| 4686 | x25_channel_t *chan = dev->priv; | ||
| 4687 | mbox_cmd_t *usr_cmd = (mbox_cmd_t *)chan->common.mbox; | ||
| 4688 | struct sk_buff *skb; | ||
| 4689 | int len=sizeof(unsigned char); | ||
| 4690 | |||
| 4691 | atomic_set(&chan->common.command,0); | ||
| 4692 | |||
| 4693 | /* If the sock is in the process of unlinking the | ||
| 4694 | * driver from the socket, we must get out. | ||
| 4695 | * This never happends but is a sanity check. */ | ||
| 4696 | if (test_bit(0,&chan->common.common_critical)){ | ||
| 4697 | return; | ||
| 4698 | } | ||
| 4699 | |||
| 4700 | if (!usr_cmd || !chan->common.sk || !chan->common.func){ | ||
| 4701 | DBG_PRINTK(KERN_INFO "Delay result: Sock not bounded sk: %u, func: %u, mbox: %u\n", | ||
| 4702 | (unsigned int)chan->common.sk, | ||
| 4703 | (unsigned int)chan->common.func, | ||
| 4704 | (unsigned int)usr_cmd); | ||
| 4705 | return; | ||
| 4706 | } | ||
| 4707 | |||
| 4708 | memcpy(&usr_cmd->cmd, &mbox->cmd, sizeof(TX25Cmd)); | ||
| 4709 | if (mbox->cmd.length > 0){ | ||
| 4710 | memcpy(usr_cmd->data, mbox->data, mbox->cmd.length); | ||
| 4711 | } | ||
| 4712 | |||
| 4713 | if (alloc_and_init_skb_buf(card,&skb,len)){ | ||
| 4714 | printk(KERN_INFO "Delay result: No sock buffers\n"); | ||
| 4715 | return; | ||
| 4716 | } | ||
| 4717 | |||
| 4718 | memcpy(skb_put(skb,len),&mbox->cmd.command,len); | ||
| 4719 | |||
| 4720 | skb->mac.raw = skb->data; | ||
| 4721 | skb->pkt_type = WAN_PACKET_CMD; | ||
| 4722 | |||
| 4723 | chan->common.func(skb,dev,chan->common.sk); | ||
| 4724 | } | ||
| 4725 | |||
| 4726 | /*=============================================================== | ||
| 4727 | * clear_confirm_event | ||
| 4728 | * | ||
| 4729 | * Pass the clear confirmation event up the sock. The | ||
| 4730 | * API will disconnect only after the clear confirmation | ||
| 4731 | * has been received. | ||
| 4732 | * | ||
| 4733 | * Depending on the state, clear confirmation could | ||
| 4734 | * be an OOB event, or a result of an API command. | ||
| 4735 | *===============================================================*/ | ||
| 4736 | |||
| 4737 | static int clear_confirm_event (sdla_t *card, TX25Mbox* mb) | ||
| 4738 | { | ||
| 4739 | struct net_device *dev; | ||
| 4740 | x25_channel_t *chan; | ||
| 4741 | unsigned char old_state; | ||
| 4742 | |||
| 4743 | dev = find_channel(card,mb->cmd.lcn); | ||
| 4744 | if (!dev){ | ||
| 4745 | DBG_PRINTK(KERN_INFO "%s: *** GOT CLEAR BUT NO DEV %i\n", | ||
| 4746 | card->devname,mb->cmd.lcn); | ||
| 4747 | return 0; | ||
| 4748 | } | ||
| 4749 | |||
| 4750 | chan=dev->priv; | ||
| 4751 | DBG_PRINTK(KERN_INFO "%s: GOT CLEAR CONFIRM %s: Mbox lcn %i Chan lcn %i\n", | ||
| 4752 | card->devname, dev->name, mb->cmd.lcn, chan->common.lcn); | ||
| 4753 | |||
| 4754 | /* If not API fall through to default. | ||
| 4755 | * If API, send the result to a waiting | ||
| 4756 | * socket. | ||
| 4757 | */ | ||
| 4758 | |||
| 4759 | old_state = chan->common.state; | ||
| 4760 | set_chan_state(dev, WAN_DISCONNECTED); | ||
| 4761 | |||
| 4762 | if (chan->common.usedby == API){ | ||
| 4763 | switch (old_state) { | ||
| 4764 | |||
| 4765 | case WAN_DISCONNECTING: | ||
| 4766 | case WAN_CONNECTING: | ||
| 4767 | send_delayed_cmd_result(card,dev,mb); | ||
| 4768 | break; | ||
| 4769 | case WAN_CONNECTED: | ||
| 4770 | send_oob_msg(card,dev,mb); | ||
| 4771 | break; | ||
| 4772 | } | ||
| 4773 | return 1; | ||
| 4774 | } | ||
| 4775 | |||
| 4776 | return 0; | ||
| 4777 | } | ||
| 4778 | |||
| 4779 | /*=============================================================== | ||
| 4780 | * send_oob_msg | ||
| 4781 | * | ||
| 4782 | * Construct an NEM Message and pass it up the connected | ||
| 4783 | * sock. If the sock is not bounded discard the NEM. | ||
| 4784 | * | ||
| 4785 | *===============================================================*/ | ||
| 4786 | |||
| 4787 | static void send_oob_msg(sdla_t *card, struct net_device *dev, TX25Mbox *mbox) | ||
| 4788 | { | ||
| 4789 | x25_channel_t *chan = dev->priv; | ||
| 4790 | mbox_cmd_t *usr_cmd = (mbox_cmd_t *)chan->common.mbox; | ||
| 4791 | struct sk_buff *skb; | ||
| 4792 | int len=sizeof(x25api_hdr_t)+mbox->cmd.length; | ||
| 4793 | x25api_t *api_hdr; | ||
| 4794 | |||
| 4795 | /* If the sock is in the process of unlinking the | ||
| 4796 | * driver from the socket, we must get out. | ||
| 4797 | * This never happends but is a sanity check. */ | ||
| 4798 | if (test_bit(0,&chan->common.common_critical)){ | ||
| 4799 | return; | ||
| 4800 | } | ||
| 4801 | |||
| 4802 | if (!usr_cmd || !chan->common.sk || !chan->common.func){ | ||
| 4803 | DBG_PRINTK(KERN_INFO "OOB MSG: Sock not bounded\n"); | ||
| 4804 | return; | ||
| 4805 | } | ||
| 4806 | |||
| 4807 | memcpy(&usr_cmd->cmd, &mbox->cmd, sizeof(TX25Cmd)); | ||
| 4808 | if (mbox->cmd.length > 0){ | ||
| 4809 | memcpy(usr_cmd->data, mbox->data, mbox->cmd.length); | ||
| 4810 | } | ||
| 4811 | |||
| 4812 | if (alloc_and_init_skb_buf(card,&skb,len)){ | ||
| 4813 | printk(KERN_INFO "%s: OOB MSG: No sock buffers\n",card->devname); | ||
| 4814 | return; | ||
| 4815 | } | ||
| 4816 | |||
| 4817 | api_hdr = (x25api_t*)skb_put(skb,len); | ||
| 4818 | api_hdr->hdr.pktType = mbox->cmd.pktType & 0x7F; | ||
| 4819 | api_hdr->hdr.qdm = mbox->cmd.qdm; | ||
| 4820 | api_hdr->hdr.cause = mbox->cmd.cause; | ||
| 4821 | api_hdr->hdr.diagn = mbox->cmd.diagn; | ||
| 4822 | api_hdr->hdr.length = mbox->cmd.length; | ||
| 4823 | api_hdr->hdr.result = mbox->cmd.result; | ||
| 4824 | api_hdr->hdr.lcn = mbox->cmd.lcn; | ||
| 4825 | |||
| 4826 | if (mbox->cmd.length > 0){ | ||
| 4827 | memcpy(api_hdr->data,mbox->data,mbox->cmd.length); | ||
| 4828 | } | ||
| 4829 | |||
| 4830 | skb->mac.raw = skb->data; | ||
| 4831 | skb->pkt_type = WAN_PACKET_ERR; | ||
| 4832 | |||
| 4833 | if (chan->common.func(skb,dev,chan->common.sk) < 0){ | ||
| 4834 | if (bh_enqueue(dev,skb)){ | ||
| 4835 | printk(KERN_INFO "%s: Dropping OOB MSG\n",card->devname); | ||
| 4836 | dev_kfree_skb_any(skb); | ||
| 4837 | } | ||
| 4838 | } | ||
| 4839 | |||
| 4840 | DBG_PRINTK(KERN_INFO "%s: OOB MSG OK, %s, lcn %i\n", | ||
| 4841 | card->devname, dev->name, mbox->cmd.lcn); | ||
| 4842 | } | ||
| 4843 | |||
| 4844 | /*=============================================================== | ||
| 4845 | * alloc_and_init_skb_buf | ||
| 4846 | * | ||
| 4847 | * Allocate and initialize an skb buffer. | ||
| 4848 | * | ||
| 4849 | *===============================================================*/ | ||
| 4850 | |||
| 4851 | static int alloc_and_init_skb_buf (sdla_t *card, struct sk_buff **skb, int len) | ||
| 4852 | { | ||
| 4853 | struct sk_buff *new_skb = *skb; | ||
| 4854 | |||
| 4855 | new_skb = dev_alloc_skb(len + X25_HRDHDR_SZ); | ||
| 4856 | if (new_skb == NULL){ | ||
| 4857 | printk(KERN_INFO "%s: no socket buffers available!\n", | ||
| 4858 | card->devname); | ||
| 4859 | return 1; | ||
| 4860 | } | ||
| 4861 | |||
| 4862 | if (skb_tailroom(new_skb) < len){ | ||
| 4863 | /* No room for the packet. Call off the whole thing! */ | ||
| 4864 | dev_kfree_skb_any(new_skb); | ||
| 4865 | printk(KERN_INFO "%s: Listen: unexpectedly long packet sequence\n" | ||
| 4866 | ,card->devname); | ||
| 4867 | *skb = NULL; | ||
| 4868 | return 1; | ||
| 4869 | } | ||
| 4870 | |||
| 4871 | *skb = new_skb; | ||
| 4872 | return 0; | ||
| 4873 | |||
| 4874 | } | ||
| 4875 | |||
| 4876 | /*=============================================================== | ||
| 4877 | * api_oob_event | ||
| 4878 | * | ||
| 4879 | * Send an OOB event up to the sock | ||
| 4880 | * | ||
| 4881 | *===============================================================*/ | ||
| 4882 | |||
| 4883 | static void api_oob_event (sdla_t *card,TX25Mbox *mbox) | ||
| 4884 | { | ||
| 4885 | struct net_device *dev = find_channel(card, mbox->cmd.lcn); | ||
| 4886 | x25_channel_t *chan; | ||
| 4887 | |||
| 4888 | if (!dev) | ||
| 4889 | return; | ||
| 4890 | |||
| 4891 | chan=dev->priv; | ||
| 4892 | |||
| 4893 | if (chan->common.usedby == API) | ||
| 4894 | send_oob_msg(card,dev,mbox); | ||
| 4895 | |||
| 4896 | } | ||
| 4897 | |||
| 4898 | |||
| 4899 | |||
| 4900 | |||
| 4901 | static int channel_disconnect(sdla_t* card, struct net_device *dev) | ||
| 4902 | { | ||
| 4903 | |||
| 4904 | int err; | ||
| 4905 | x25_channel_t *chan = dev->priv; | ||
| 4906 | |||
| 4907 | DBG_PRINTK(KERN_INFO "%s: TIMER: %s, Device down disconnecting\n", | ||
| 4908 | card->devname,dev->name); | ||
| 4909 | |||
| 4910 | if (chan->common.svc){ | ||
| 4911 | err = x25_clear_call(card,chan->common.lcn,0,0); | ||
| 4912 | }else{ | ||
| 4913 | /* If channel is PVC or LAPB HDLC, there is no call | ||
| 4914 | * to be cleared, thus drop down to the default | ||
| 4915 | * area | ||
| 4916 | */ | ||
| 4917 | err = 1; | ||
| 4918 | } | ||
| 4919 | |||
| 4920 | switch (err){ | ||
| 4921 | |||
| 4922 | case X25RES_CHANNEL_IN_USE: | ||
| 4923 | case X25RES_NOT_READY: | ||
| 4924 | err = TRY_CMD_AGAIN; | ||
| 4925 | break; | ||
| 4926 | case CMD_OK: | ||
| 4927 | DBG_PRINTK(KERN_INFO "CALL CLEAR OK: Dev %s Chan Lcn %i\n", | ||
| 4928 | dev->name,chan->common.lcn); | ||
| 4929 | |||
| 4930 | set_chan_state(dev,WAN_DISCONNECTING); | ||
| 4931 | atomic_set(&chan->common.command,0); | ||
| 4932 | err = DELAY_RESULT; | ||
| 4933 | break; | ||
| 4934 | default: | ||
| 4935 | /* If LAPB HDLC protocol, bring the whole link down | ||
| 4936 | * once the application terminates | ||
| 4937 | */ | ||
| 4938 | |||
| 4939 | set_chan_state(dev,WAN_DISCONNECTED); | ||
| 4940 | |||
| 4941 | if (card->u.x.LAPB_hdlc){ | ||
| 4942 | DBG_PRINTK(KERN_INFO "LAPB: Disconnecting Link\n"); | ||
| 4943 | hdlc_link_down (card); | ||
| 4944 | } | ||
| 4945 | atomic_set(&chan->common.command,0); | ||
| 4946 | err = RETURN_RESULT; | ||
| 4947 | break; | ||
| 4948 | } | ||
| 4949 | |||
| 4950 | return err; | ||
| 4951 | } | ||
| 4952 | |||
| 4953 | static void hdlc_link_down (sdla_t *card) | ||
| 4954 | { | ||
| 4955 | TX25Mbox* mbox = card->mbox; | ||
| 4956 | int retry = 5; | ||
| 4957 | int err=0; | ||
| 4958 | |||
| 4959 | do { | ||
| 4960 | memset(mbox,0,sizeof(TX25Mbox)); | ||
| 4961 | mbox->cmd.command = X25_HDLC_LINK_DISC; | ||
| 4962 | mbox->cmd.length = 1; | ||
| 4963 | mbox->data[0]=0; | ||
| 4964 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 4965 | |||
| 4966 | } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_DISC, 0)); | ||
| 4967 | |||
| 4968 | if (err) | ||
| 4969 | printk(KERN_INFO "%s: Hdlc Link Down Failed %x\n",card->devname,err); | ||
| 4970 | |||
| 4971 | disconnect (card); | ||
| 4972 | |||
| 4973 | } | ||
| 4974 | |||
| 4975 | static int check_bad_command(sdla_t* card, struct net_device *dev) | ||
| 4976 | { | ||
| 4977 | x25_channel_t *chan = dev->priv; | ||
| 4978 | int bad_cmd = 0; | ||
| 4979 | |||
| 4980 | switch (atomic_read(&chan->common.command)&0x7F){ | ||
| 4981 | |||
| 4982 | case X25_PLACE_CALL: | ||
| 4983 | if (chan->common.state != WAN_DISCONNECTED) | ||
| 4984 | bad_cmd=1; | ||
| 4985 | break; | ||
| 4986 | case X25_CLEAR_CALL: | ||
| 4987 | if (chan->common.state == WAN_DISCONNECTED) | ||
| 4988 | bad_cmd=1; | ||
| 4989 | break; | ||
| 4990 | case X25_ACCEPT_CALL: | ||
| 4991 | if (chan->common.state != WAN_CONNECTING) | ||
| 4992 | bad_cmd=1; | ||
| 4993 | break; | ||
| 4994 | case X25_RESET: | ||
| 4995 | if (chan->common.state != WAN_CONNECTED) | ||
| 4996 | bad_cmd=1; | ||
| 4997 | break; | ||
| 4998 | default: | ||
| 4999 | bad_cmd=1; | ||
| 5000 | break; | ||
| 5001 | } | ||
| 5002 | |||
| 5003 | if (bad_cmd){ | ||
| 5004 | printk(KERN_INFO "%s: Invalid State, BAD Command %x, dev %s, lcn %i, st %i\n", | ||
| 5005 | card->devname,atomic_read(&chan->common.command),dev->name, | ||
| 5006 | chan->common.lcn, chan->common.state); | ||
| 5007 | } | ||
| 5008 | |||
| 5009 | return bad_cmd; | ||
| 5010 | } | ||
| 5011 | |||
| 5012 | |||
| 5013 | |||
| 5014 | /*************************** XPIPEMON FUNCTIONS **************************/ | ||
| 5015 | |||
| 5016 | /*============================================================================== | ||
| 5017 | * Process UDP call of type XPIPE | ||
| 5018 | */ | ||
| 5019 | |||
| 5020 | static int process_udp_mgmt_pkt(sdla_t *card) | ||
| 5021 | { | ||
| 5022 | int c_retry = MAX_CMD_RETRY; | ||
| 5023 | unsigned int len; | ||
| 5024 | struct sk_buff *new_skb; | ||
| 5025 | TX25Mbox *mbox = card->mbox; | ||
| 5026 | int err; | ||
| 5027 | int udp_mgmt_req_valid = 1; | ||
| 5028 | struct net_device *dev; | ||
| 5029 | x25_channel_t *chan; | ||
| 5030 | unsigned short lcn; | ||
| 5031 | struct timeval tv; | ||
| 5032 | |||
| 5033 | |||
| 5034 | x25_udp_pkt_t *x25_udp_pkt; | ||
| 5035 | x25_udp_pkt = (x25_udp_pkt_t *)card->u.x.udp_pkt_data; | ||
| 5036 | |||
| 5037 | dev = card->u.x.udp_dev; | ||
| 5038 | chan = dev->priv; | ||
| 5039 | lcn = chan->common.lcn; | ||
| 5040 | |||
| 5041 | switch(x25_udp_pkt->cblock.command) { | ||
| 5042 | |||
| 5043 | /* XPIPE_ENABLE_TRACE */ | ||
| 5044 | case XPIPE_ENABLE_TRACING: | ||
| 5045 | |||
| 5046 | /* XPIPE_GET_TRACE_INFO */ | ||
| 5047 | case XPIPE_GET_TRACE_INFO: | ||
| 5048 | |||
| 5049 | /* SET FT1 MODE */ | ||
| 5050 | case XPIPE_SET_FT1_MODE: | ||
| 5051 | |||
| 5052 | if(card->u.x.udp_pkt_src == UDP_PKT_FRM_NETWORK) { | ||
| 5053 | ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_direction_err; | ||
| 5054 | udp_mgmt_req_valid = 0; | ||
| 5055 | break; | ||
| 5056 | } | ||
| 5057 | |||
| 5058 | /* XPIPE_FT1_READ_STATUS */ | ||
| 5059 | case XPIPE_FT1_READ_STATUS: | ||
| 5060 | |||
| 5061 | /* FT1 MONITOR STATUS */ | ||
| 5062 | case XPIPE_FT1_STATUS_CTRL: | ||
| 5063 | if(card->hw.fwid != SFID_X25_508) { | ||
| 5064 | ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_type_err; | ||
| 5065 | udp_mgmt_req_valid = 0; | ||
| 5066 | break; | ||
| 5067 | } | ||
| 5068 | default: | ||
| 5069 | break; | ||
| 5070 | } | ||
| 5071 | |||
| 5072 | if(!udp_mgmt_req_valid) { | ||
| 5073 | /* set length to 0 */ | ||
| 5074 | x25_udp_pkt->cblock.length = 0; | ||
| 5075 | /* set return code */ | ||
| 5076 | x25_udp_pkt->cblock.result = (card->hw.fwid != SFID_X25_508) ? 0x1F : 0xCD; | ||
| 5077 | |||
| 5078 | } else { | ||
| 5079 | |||
| 5080 | switch (x25_udp_pkt->cblock.command) { | ||
| 5081 | |||
| 5082 | |||
| 5083 | case XPIPE_FLUSH_DRIVER_STATS: | ||
| 5084 | init_x25_channel_struct(chan); | ||
| 5085 | init_global_statistics(card); | ||
| 5086 | mbox->cmd.length = 0; | ||
| 5087 | break; | ||
| 5088 | |||
| 5089 | |||
| 5090 | case XPIPE_DRIVER_STAT_IFSEND: | ||
| 5091 | memcpy(x25_udp_pkt->data, &chan->if_send_stat, sizeof(if_send_stat_t)); | ||
| 5092 | mbox->cmd.length = sizeof(if_send_stat_t); | ||
| 5093 | x25_udp_pkt->cblock.length = mbox->cmd.length; | ||
| 5094 | break; | ||
| 5095 | |||
| 5096 | case XPIPE_DRIVER_STAT_INTR: | ||
| 5097 | memcpy(&x25_udp_pkt->data[0], &card->statistics, sizeof(global_stats_t)); | ||
| 5098 | memcpy(&x25_udp_pkt->data[sizeof(global_stats_t)], | ||
| 5099 | &chan->rx_intr_stat, sizeof(rx_intr_stat_t)); | ||
| 5100 | |||
| 5101 | mbox->cmd.length = sizeof(global_stats_t) + | ||
| 5102 | sizeof(rx_intr_stat_t); | ||
| 5103 | x25_udp_pkt->cblock.length = mbox->cmd.length; | ||
| 5104 | break; | ||
| 5105 | |||
| 5106 | case XPIPE_DRIVER_STAT_GEN: | ||
| 5107 | memcpy(x25_udp_pkt->data, | ||
| 5108 | &chan->pipe_mgmt_stat.UDP_PIPE_mgmt_kmalloc_err, | ||
| 5109 | sizeof(pipe_mgmt_stat_t)); | ||
| 5110 | |||
| 5111 | memcpy(&x25_udp_pkt->data[sizeof(pipe_mgmt_stat_t)], | ||
| 5112 | &card->statistics, sizeof(global_stats_t)); | ||
| 5113 | |||
| 5114 | x25_udp_pkt->cblock.result = 0; | ||
| 5115 | x25_udp_pkt->cblock.length = sizeof(global_stats_t)+ | ||
| 5116 | sizeof(rx_intr_stat_t); | ||
| 5117 | mbox->cmd.length = x25_udp_pkt->cblock.length; | ||
| 5118 | break; | ||
| 5119 | |||
| 5120 | case XPIPE_ROUTER_UP_TIME: | ||
| 5121 | do_gettimeofday(&tv); | ||
| 5122 | chan->router_up_time = tv.tv_sec - chan->router_start_time; | ||
| 5123 | *(unsigned long *)&x25_udp_pkt->data = chan->router_up_time; | ||
| 5124 | x25_udp_pkt->cblock.length = mbox->cmd.length = 4; | ||
| 5125 | x25_udp_pkt->cblock.result = 0; | ||
| 5126 | break; | ||
| 5127 | |||
| 5128 | default : | ||
| 5129 | |||
| 5130 | do { | ||
| 5131 | memcpy(&mbox->cmd, &x25_udp_pkt->cblock.command, sizeof(TX25Cmd)); | ||
| 5132 | if(mbox->cmd.length){ | ||
| 5133 | memcpy(&mbox->data, | ||
| 5134 | (char *)x25_udp_pkt->data, | ||
| 5135 | mbox->cmd.length); | ||
| 5136 | } | ||
| 5137 | |||
| 5138 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 5139 | } while (err && c_retry-- && x25_error(card, err, mbox->cmd.command, 0)); | ||
| 5140 | |||
| 5141 | |||
| 5142 | if ( err == CMD_OK || | ||
| 5143 | (err == 1 && | ||
| 5144 | (mbox->cmd.command == 0x06 || | ||
| 5145 | mbox->cmd.command == 0x16) ) ){ | ||
| 5146 | |||
| 5147 | ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_OK; | ||
| 5148 | } else { | ||
| 5149 | ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_timeout; | ||
| 5150 | } | ||
| 5151 | |||
| 5152 | /* copy the result back to our buffer */ | ||
| 5153 | memcpy(&x25_udp_pkt->cblock.command, &mbox->cmd, sizeof(TX25Cmd)); | ||
| 5154 | |||
| 5155 | if(mbox->cmd.length) { | ||
| 5156 | memcpy(&x25_udp_pkt->data, &mbox->data, mbox->cmd.length); | ||
| 5157 | } | ||
| 5158 | break; | ||
| 5159 | |||
| 5160 | } //switch | ||
| 5161 | |||
| 5162 | } | ||
| 5163 | |||
| 5164 | /* Fill UDP TTL */ | ||
| 5165 | |||
| 5166 | x25_udp_pkt->ip_pkt.ttl = card->wandev.ttl; | ||
| 5167 | len = reply_udp(card->u.x.udp_pkt_data, mbox->cmd.length); | ||
| 5168 | |||
| 5169 | |||
| 5170 | if(card->u.x.udp_pkt_src == UDP_PKT_FRM_NETWORK) { | ||
| 5171 | |||
| 5172 | err = x25_send(card, lcn, 0, len, card->u.x.udp_pkt_data); | ||
| 5173 | if (!err) | ||
| 5174 | ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_send_passed; | ||
| 5175 | else | ||
| 5176 | ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_send_failed; | ||
| 5177 | |||
| 5178 | } else { | ||
| 5179 | |||
| 5180 | /* Allocate socket buffer */ | ||
| 5181 | if((new_skb = dev_alloc_skb(len)) != NULL) { | ||
| 5182 | void *buf; | ||
| 5183 | |||
| 5184 | /* copy data into new_skb */ | ||
| 5185 | buf = skb_put(new_skb, len); | ||
| 5186 | memcpy(buf, card->u.x.udp_pkt_data, len); | ||
| 5187 | |||
| 5188 | /* Decapsulate packet and pass it up the protocol | ||
| 5189 | stack */ | ||
| 5190 | new_skb->dev = dev; | ||
| 5191 | |||
| 5192 | if (chan->common.usedby == API) | ||
| 5193 | new_skb->protocol = htons(X25_PROT); | ||
| 5194 | else | ||
| 5195 | new_skb->protocol = htons(ETH_P_IP); | ||
| 5196 | |||
| 5197 | new_skb->mac.raw = new_skb->data; | ||
| 5198 | |||
| 5199 | netif_rx(new_skb); | ||
| 5200 | ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_stack; | ||
| 5201 | |||
| 5202 | } else { | ||
| 5203 | ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_no_socket; | ||
| 5204 | printk(KERN_INFO | ||
| 5205 | "%s: UDP mgmt cmnd, no socket buffers available!\n", | ||
| 5206 | card->devname); | ||
| 5207 | } | ||
| 5208 | } | ||
| 5209 | |||
| 5210 | card->u.x.udp_pkt_lgth = 0; | ||
| 5211 | |||
| 5212 | return 1; | ||
| 5213 | } | ||
| 5214 | |||
| 5215 | |||
| 5216 | /*============================================================================== | ||
| 5217 | * Determine what type of UDP call it is. DRVSTATS or XPIPE8ND ? | ||
| 5218 | */ | ||
| 5219 | static int udp_pkt_type( struct sk_buff *skb, sdla_t* card ) | ||
| 5220 | { | ||
| 5221 | x25_udp_pkt_t *x25_udp_pkt = (x25_udp_pkt_t *)skb->data; | ||
| 5222 | |||
| 5223 | if((x25_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && | ||
| 5224 | (x25_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45) && | ||
| 5225 | (x25_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) && | ||
| 5226 | (x25_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) { | ||
| 5227 | |||
| 5228 | if(!strncmp(x25_udp_pkt->wp_mgmt.signature, | ||
| 5229 | UDPMGMT_XPIPE_SIGNATURE, 8)){ | ||
| 5230 | return UDP_XPIPE_TYPE; | ||
| 5231 | }else{ | ||
| 5232 | printk(KERN_INFO "%s: UDP Packet, Failed Signature !\n", | ||
| 5233 | card->devname); | ||
| 5234 | } | ||
| 5235 | } | ||
| 5236 | |||
| 5237 | return UDP_INVALID_TYPE; | ||
| 5238 | } | ||
| 5239 | |||
| 5240 | |||
| 5241 | /*============================================================================ | ||
| 5242 | * Reply to UDP Management system. | ||
| 5243 | * Return nothing. | ||
| 5244 | */ | ||
| 5245 | static int reply_udp( unsigned char *data, unsigned int mbox_len ) | ||
| 5246 | { | ||
| 5247 | unsigned short len, udp_length, temp, ip_length; | ||
| 5248 | unsigned long ip_temp; | ||
| 5249 | int even_bound = 0; | ||
| 5250 | |||
| 5251 | |||
| 5252 | x25_udp_pkt_t *x25_udp_pkt = (x25_udp_pkt_t *)data; | ||
| 5253 | |||
| 5254 | /* Set length of packet */ | ||
| 5255 | len = sizeof(ip_pkt_t)+ | ||
| 5256 | sizeof(udp_pkt_t)+ | ||
| 5257 | sizeof(wp_mgmt_t)+ | ||
| 5258 | sizeof(cblock_t)+ | ||
| 5259 | mbox_len; | ||
| 5260 | |||
| 5261 | |||
| 5262 | /* fill in UDP reply */ | ||
| 5263 | x25_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; | ||
| 5264 | |||
| 5265 | /* fill in UDP length */ | ||
| 5266 | udp_length = sizeof(udp_pkt_t)+ | ||
| 5267 | sizeof(wp_mgmt_t)+ | ||
| 5268 | sizeof(cblock_t)+ | ||
| 5269 | mbox_len; | ||
| 5270 | |||
| 5271 | |||
| 5272 | /* put it on an even boundary */ | ||
| 5273 | if ( udp_length & 0x0001 ) { | ||
| 5274 | udp_length += 1; | ||
| 5275 | len += 1; | ||
| 5276 | even_bound = 1; | ||
| 5277 | } | ||
| 5278 | |||
| 5279 | temp = (udp_length<<8)|(udp_length>>8); | ||
| 5280 | x25_udp_pkt->udp_pkt.udp_length = temp; | ||
| 5281 | |||
| 5282 | /* swap UDP ports */ | ||
| 5283 | temp = x25_udp_pkt->udp_pkt.udp_src_port; | ||
| 5284 | x25_udp_pkt->udp_pkt.udp_src_port = | ||
| 5285 | x25_udp_pkt->udp_pkt.udp_dst_port; | ||
| 5286 | x25_udp_pkt->udp_pkt.udp_dst_port = temp; | ||
| 5287 | |||
| 5288 | |||
| 5289 | |||
| 5290 | /* add UDP pseudo header */ | ||
| 5291 | temp = 0x1100; | ||
| 5292 | *((unsigned short *) | ||
| 5293 | (x25_udp_pkt->data+mbox_len+even_bound)) = temp; | ||
| 5294 | temp = (udp_length<<8)|(udp_length>>8); | ||
| 5295 | *((unsigned short *) | ||
| 5296 | (x25_udp_pkt->data+mbox_len+even_bound+2)) = temp; | ||
| 5297 | |||
| 5298 | /* calculate UDP checksum */ | ||
| 5299 | x25_udp_pkt->udp_pkt.udp_checksum = 0; | ||
| 5300 | |||
| 5301 | x25_udp_pkt->udp_pkt.udp_checksum = | ||
| 5302 | calc_checksum(&data[UDP_OFFSET], udp_length+UDP_OFFSET); | ||
| 5303 | |||
| 5304 | /* fill in IP length */ | ||
| 5305 | ip_length = len; | ||
| 5306 | temp = (ip_length<<8)|(ip_length>>8); | ||
| 5307 | x25_udp_pkt->ip_pkt.total_length = temp; | ||
| 5308 | |||
| 5309 | /* swap IP addresses */ | ||
| 5310 | ip_temp = x25_udp_pkt->ip_pkt.ip_src_address; | ||
| 5311 | x25_udp_pkt->ip_pkt.ip_src_address = | ||
| 5312 | x25_udp_pkt->ip_pkt.ip_dst_address; | ||
| 5313 | x25_udp_pkt->ip_pkt.ip_dst_address = ip_temp; | ||
| 5314 | |||
| 5315 | |||
| 5316 | /* fill in IP checksum */ | ||
| 5317 | x25_udp_pkt->ip_pkt.hdr_checksum = 0; | ||
| 5318 | x25_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data, sizeof(ip_pkt_t)); | ||
| 5319 | |||
| 5320 | return len; | ||
| 5321 | } /* reply_udp */ | ||
| 5322 | |||
| 5323 | unsigned short calc_checksum (char *data, int len) | ||
| 5324 | { | ||
| 5325 | unsigned short temp; | ||
| 5326 | unsigned long sum=0; | ||
| 5327 | int i; | ||
| 5328 | |||
| 5329 | for( i = 0; i <len; i+=2 ) { | ||
| 5330 | memcpy(&temp,&data[i],2); | ||
| 5331 | sum += (unsigned long)temp; | ||
| 5332 | } | ||
| 5333 | |||
| 5334 | while (sum >> 16 ) { | ||
| 5335 | sum = (sum & 0xffffUL) + (sum >> 16); | ||
| 5336 | } | ||
| 5337 | |||
| 5338 | temp = (unsigned short)sum; | ||
| 5339 | temp = ~temp; | ||
| 5340 | |||
| 5341 | if( temp == 0 ) | ||
| 5342 | temp = 0xffff; | ||
| 5343 | |||
| 5344 | return temp; | ||
| 5345 | } | ||
| 5346 | |||
| 5347 | /*============================================================================= | ||
| 5348 | * Store a UDP management packet for later processing. | ||
| 5349 | */ | ||
| 5350 | |||
| 5351 | static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card, | ||
| 5352 | struct net_device *dev, struct sk_buff *skb, | ||
| 5353 | int lcn) | ||
| 5354 | { | ||
| 5355 | int udp_pkt_stored = 0; | ||
| 5356 | |||
| 5357 | if(!card->u.x.udp_pkt_lgth && (skb->len <= MAX_LGTH_UDP_MGNT_PKT)){ | ||
| 5358 | card->u.x.udp_pkt_lgth = skb->len; | ||
| 5359 | card->u.x.udp_type = udp_type; | ||
| 5360 | card->u.x.udp_pkt_src = udp_pkt_src; | ||
| 5361 | card->u.x.udp_lcn = lcn; | ||
| 5362 | card->u.x.udp_dev = dev; | ||
| 5363 | memcpy(card->u.x.udp_pkt_data, skb->data, skb->len); | ||
| 5364 | card->u.x.timer_int_enabled |= TMR_INT_ENABLED_UDP_PKT; | ||
| 5365 | udp_pkt_stored = 1; | ||
| 5366 | |||
| 5367 | }else{ | ||
| 5368 | printk(KERN_INFO "%s: ERROR: UDP packet not stored for LCN %d\n", | ||
| 5369 | card->devname,lcn); | ||
| 5370 | } | ||
| 5371 | |||
| 5372 | if(udp_pkt_src == UDP_PKT_FRM_STACK){ | ||
| 5373 | dev_kfree_skb_any(skb); | ||
| 5374 | }else{ | ||
| 5375 | dev_kfree_skb_any(skb); | ||
| 5376 | } | ||
| 5377 | |||
| 5378 | return(udp_pkt_stored); | ||
| 5379 | } | ||
| 5380 | |||
| 5381 | |||
| 5382 | |||
| 5383 | /*============================================================================= | ||
| 5384 | * Initial the ppp_private_area structure. | ||
| 5385 | */ | ||
| 5386 | static void init_x25_channel_struct( x25_channel_t *chan ) | ||
| 5387 | { | ||
| 5388 | memset(&chan->if_send_stat.if_send_entry,0,sizeof(if_send_stat_t)); | ||
| 5389 | memset(&chan->rx_intr_stat.rx_intr_no_socket,0,sizeof(rx_intr_stat_t)); | ||
| 5390 | memset(&chan->pipe_mgmt_stat.UDP_PIPE_mgmt_kmalloc_err,0,sizeof(pipe_mgmt_stat_t)); | ||
| 5391 | } | ||
| 5392 | |||
| 5393 | /*============================================================================ | ||
| 5394 | * Initialize Global Statistics | ||
| 5395 | */ | ||
| 5396 | static void init_global_statistics( sdla_t *card ) | ||
| 5397 | { | ||
| 5398 | memset(&card->statistics.isr_entry,0,sizeof(global_stats_t)); | ||
| 5399 | } | ||
| 5400 | |||
| 5401 | |||
| 5402 | /*=============================================================== | ||
| 5403 | * SMP Support | ||
| 5404 | * ==============================================================*/ | ||
| 5405 | |||
| 5406 | static void S508_S514_lock(sdla_t *card, unsigned long *smp_flags) | ||
| 5407 | { | ||
| 5408 | spin_lock_irqsave(&card->wandev.lock, *smp_flags); | ||
| 5409 | } | ||
| 5410 | static void S508_S514_unlock(sdla_t *card, unsigned long *smp_flags) | ||
| 5411 | { | ||
| 5412 | spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); | ||
| 5413 | } | ||
| 5414 | |||
| 5415 | /*=============================================================== | ||
| 5416 | * x25_timer_routine | ||
| 5417 | * | ||
| 5418 | * A more efficient polling routine. Each half a second | ||
| 5419 | * queue a polling task. We want to do the polling in a | ||
| 5420 | * task not timer, because timer runs in interrupt time. | ||
| 5421 | * | ||
| 5422 | * FIXME Polling should be rethinked. | ||
| 5423 | *==============================================================*/ | ||
| 5424 | |||
| 5425 | static void x25_timer_routine(unsigned long data) | ||
| 5426 | { | ||
| 5427 | sdla_t *card = (sdla_t*)data; | ||
| 5428 | |||
| 5429 | if (!card->wandev.dev){ | ||
| 5430 | printk(KERN_INFO "%s: Stopping the X25 Poll Timer: No Dev.\n", | ||
| 5431 | card->devname); | ||
| 5432 | return; | ||
| 5433 | } | ||
| 5434 | |||
| 5435 | if (card->open_cnt != card->u.x.num_of_ch){ | ||
| 5436 | printk(KERN_INFO "%s: Stopping the X25 Poll Timer: Interface down.\n", | ||
| 5437 | card->devname); | ||
| 5438 | return; | ||
| 5439 | } | ||
| 5440 | |||
| 5441 | if (test_bit(PERI_CRIT,&card->wandev.critical)){ | ||
| 5442 | printk(KERN_INFO "%s: Stopping the X25 Poll Timer: Shutting down.\n", | ||
| 5443 | card->devname); | ||
| 5444 | return; | ||
| 5445 | } | ||
| 5446 | |||
| 5447 | if (!test_and_set_bit(POLL_CRIT,&card->wandev.critical)){ | ||
| 5448 | trigger_x25_poll(card); | ||
| 5449 | } | ||
| 5450 | |||
| 5451 | card->u.x.x25_timer.expires=jiffies+(HZ>>1); | ||
| 5452 | add_timer(&card->u.x.x25_timer); | ||
| 5453 | return; | ||
| 5454 | } | ||
| 5455 | |||
| 5456 | void disable_comm_shutdown(sdla_t *card) | ||
| 5457 | { | ||
| 5458 | TX25Mbox* mbox = card->mbox; | ||
| 5459 | int err; | ||
| 5460 | |||
| 5461 | /* Turn of interrutps */ | ||
| 5462 | mbox->data[0] = 0; | ||
| 5463 | if (card->hw.fwid == SFID_X25_508){ | ||
| 5464 | mbox->data[1] = card->hw.irq; | ||
| 5465 | mbox->data[2] = 2; | ||
| 5466 | mbox->cmd.length = 3; | ||
| 5467 | }else { | ||
| 5468 | mbox->cmd.length = 1; | ||
| 5469 | } | ||
| 5470 | mbox->cmd.command = X25_SET_INTERRUPT_MODE; | ||
| 5471 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 5472 | if (err) | ||
| 5473 | printk(KERN_INFO "INTERRUPT OFF FAIED %x\n",err); | ||
| 5474 | |||
| 5475 | /* Bring down HDLC */ | ||
| 5476 | mbox->cmd.command = X25_HDLC_LINK_CLOSE; | ||
| 5477 | mbox->cmd.length = 0; | ||
| 5478 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 5479 | if (err) | ||
| 5480 | printk(KERN_INFO "LINK CLOSED FAILED %x\n",err); | ||
| 5481 | |||
| 5482 | |||
| 5483 | /* Brind down DTR */ | ||
| 5484 | mbox->data[0] = 0; | ||
| 5485 | mbox->data[2] = 0; | ||
| 5486 | mbox->data[1] = 0x01; | ||
| 5487 | mbox->cmd.length = 3; | ||
| 5488 | mbox->cmd.command = X25_SET_GLOBAL_VARS; | ||
| 5489 | err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; | ||
| 5490 | if (err) | ||
| 5491 | printk(KERN_INFO "DTR DOWN FAILED %x\n",err); | ||
| 5492 | |||
| 5493 | } | ||
| 5494 | |||
| 5495 | MODULE_LICENSE("GPL"); | ||
| 5496 | |||
| 5497 | /****** End *****************************************************************/ | ||
diff --git a/drivers/net/wan/sdladrv.c b/drivers/net/wan/sdladrv.c deleted file mode 100644 index 032c0f81928e..000000000000 --- a/drivers/net/wan/sdladrv.c +++ /dev/null | |||
| @@ -1,2314 +0,0 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * sdladrv.c SDLA Support Module. Main module. | ||
| 3 | * | ||
| 4 | * This module is a library of common hardware-specific functions | ||
| 5 | * used by all Sangoma drivers. | ||
| 6 | * | ||
| 7 | * Author: Gideon Hack | ||
| 8 | * | ||
| 9 | * Copyright: (c) 1995-2000 Sangoma Technologies Inc. | ||
| 10 | * | ||
| 11 | * This program is free software; you can redistribute it and/or | ||
| 12 | * modify it under the terms of the GNU General Public License | ||
| 13 | * as published by the Free Software Foundation; either version | ||
| 14 | * 2 of the License, or (at your option) any later version. | ||
| 15 | * ============================================================================ | ||
| 16 | * Mar 20, 2001 Nenad Corbic Added the auto_pci_cfg filed, to support | ||
| 17 | * the PCISLOT #0. | ||
| 18 | * Apr 04, 2000 Nenad Corbic Fixed the auto memory detection code. | ||
| 19 | * The memory test at address 0xC8000. | ||
| 20 | * Mar 09, 2000 Nenad Corbic Added Gideon's Bug Fix: clear pci | ||
| 21 | * interrupt flags on initial load. | ||
| 22 | * Jun 02, 1999 Gideon Hack Added support for the S514 adapter. | ||
| 23 | * Updates for Linux 2.2.X kernels. | ||
| 24 | * Sep 17, 1998 Jaspreet Singh Updates for linux 2.2.X kernels | ||
| 25 | * Dec 20, 1996 Gene Kozin Version 3.0.0. Complete overhaul. | ||
| 26 | * Jul 12, 1996 Gene Kozin Changes for Linux 2.0 compatibility. | ||
| 27 | * Jun 12, 1996 Gene Kozin Added support for S503 card. | ||
| 28 | * Apr 30, 1996 Gene Kozin SDLA hardware interrupt is acknowledged before | ||
| 29 | * calling protocolspecific ISR. | ||
| 30 | * Register I/O ports with Linux kernel. | ||
| 31 | * Miscellaneous bug fixes. | ||
| 32 | * Dec 20, 1995 Gene Kozin Fixed a bug in interrupt routine. | ||
| 33 | * Oct 14, 1995 Gene Kozin Initial version. | ||
| 34 | *****************************************************************************/ | ||
| 35 | |||
| 36 | /***************************************************************************** | ||
| 37 | * Notes: | ||
| 38 | * ------ | ||
| 39 | * 1. This code is ment to be system-independent (as much as possible). To | ||
| 40 | * achive this, various macros are used to hide system-specific interfaces. | ||
| 41 | * To compile this code, one of the following constants must be defined: | ||
| 42 | * | ||
| 43 | * Platform Define | ||
| 44 | * -------- ------ | ||
| 45 | * Linux _LINUX_ | ||
| 46 | * SCO Unix _SCO_UNIX_ | ||
| 47 | * | ||
| 48 | * 2. Supported adapter types: | ||
| 49 | * | ||
| 50 | * S502A | ||
| 51 | * ES502A (S502E) | ||
| 52 | * S503 | ||
| 53 | * S507 | ||
| 54 | * S508 (S509) | ||
| 55 | * | ||
| 56 | * 3. S502A Notes: | ||
| 57 | * | ||
| 58 | * There is no separate DPM window enable/disable control in S502A. It | ||
| 59 | * opens immediately after a window number it written to the HMCR | ||
| 60 | * register. To close the window, HMCR has to be written a value | ||
| 61 | * ????1111b (e.g. 0x0F or 0xFF). | ||
| 62 | * | ||
| 63 | * S502A DPM window cannot be located at offset E000 (e.g. 0xAE000). | ||
| 64 | * | ||
| 65 | * There should be a delay of ??? before reading back S502A status | ||
| 66 | * register. | ||
| 67 | * | ||
| 68 | * 4. S502E Notes: | ||
| 69 | * | ||
| 70 | * S502E has a h/w bug: although default IRQ line state is HIGH, enabling | ||
| 71 | * interrupts by setting bit 1 of the control register (BASE) to '1' | ||
| 72 | * causes it to go LOW! Therefore, disabling interrupts by setting that | ||
| 73 | * bit to '0' causes low-to-high transition on IRQ line (ghosty | ||
| 74 | * interrupt). The same occurs when disabling CPU by resetting bit 0 of | ||
| 75 | * CPU control register (BASE+3) - see the next note. | ||
| 76 | * | ||
| 77 | * S502E CPU and DPM control is limited: | ||
| 78 | * | ||
| 79 | * o CPU cannot be stopped independently. Resetting bit 0 of the CPUi | ||
| 80 | * control register (BASE+3) shuts the board down entirely, including | ||
| 81 | * DPM; | ||
| 82 | * | ||
| 83 | * o DPM access cannot be controlled dynamically. Ones CPU is started, | ||
| 84 | * bit 1 of the control register (BASE) is used to enable/disable IRQ, | ||
| 85 | * so that access to shared memory cannot be disabled while CPU is | ||
| 86 | * running. | ||
| 87 | ****************************************************************************/ | ||
| 88 | |||
| 89 | #define _LINUX_ | ||
| 90 | |||
| 91 | #if defined(_LINUX_) /****** Linux *******************************/ | ||
| 92 | |||
| 93 | #include <linux/config.h> | ||
| 94 | #include <linux/kernel.h> /* printk(), and other useful stuff */ | ||
| 95 | #include <linux/stddef.h> /* offsetof(), etc. */ | ||
| 96 | #include <linux/errno.h> /* return codes */ | ||
| 97 | #include <linux/string.h> /* inline memset(), etc. */ | ||
| 98 | #include <linux/module.h> /* support for loadable modules */ | ||
| 99 | #include <linux/jiffies.h> /* for jiffies, HZ, etc. */ | ||
| 100 | #include <linux/sdladrv.h> /* API definitions */ | ||
| 101 | #include <linux/sdlasfm.h> /* SDLA firmware module definitions */ | ||
| 102 | #include <linux/sdlapci.h> /* SDLA PCI hardware definitions */ | ||
| 103 | #include <linux/pci.h> /* PCI defines and function prototypes */ | ||
| 104 | #include <asm/io.h> /* for inb(), outb(), etc. */ | ||
| 105 | |||
| 106 | #define _INB(port) (inb(port)) | ||
| 107 | #define _OUTB(port, byte) (outb((byte),(port))) | ||
| 108 | #define SYSTEM_TICK jiffies | ||
| 109 | |||
| 110 | #include <linux/init.h> | ||
| 111 | |||
| 112 | |||
| 113 | #elif defined(_SCO_UNIX_) /****** SCO Unix ****************************/ | ||
| 114 | |||
| 115 | #if !defined(INKERNEL) | ||
| 116 | #error This code MUST be compiled in kernel mode! | ||
| 117 | #endif | ||
| 118 | #include <sys/sdladrv.h> /* API definitions */ | ||
| 119 | #include <sys/sdlasfm.h> /* SDLA firmware module definitions */ | ||
| 120 | #include <sys/inline.h> /* for inb(), outb(), etc. */ | ||
| 121 | #define _INB(port) (inb(port)) | ||
| 122 | #define _OUTB(port, byte) (outb((port),(byte))) | ||
| 123 | #define SYSTEM_TICK lbolt | ||
| 124 | |||
| 125 | #else | ||
| 126 | #error Unknown system type! | ||
| 127 | #endif | ||
| 128 | |||
| 129 | #define MOD_VERSION 3 | ||
| 130 | #define MOD_RELEASE 0 | ||
| 131 | |||
| 132 | #define SDLA_IODELAY 100 /* I/O Rd/Wr delay, 10 works for 486DX2-66 */ | ||
| 133 | #define EXEC_DELAY 20 /* shared memory access delay, mks */ | ||
| 134 | #define EXEC_TIMEOUT (HZ*2) /* command timeout, in ticks */ | ||
| 135 | |||
| 136 | /* I/O port address range */ | ||
| 137 | #define S502A_IORANGE 3 | ||
| 138 | #define S502E_IORANGE 4 | ||
| 139 | #define S503_IORANGE 3 | ||
| 140 | #define S507_IORANGE 4 | ||
| 141 | #define S508_IORANGE 4 | ||
| 142 | |||
| 143 | /* Maximum amount of memory */ | ||
| 144 | #define S502_MAXMEM 0x10000L | ||
| 145 | #define S503_MAXMEM 0x10000L | ||
| 146 | #define S507_MAXMEM 0x40000L | ||
| 147 | #define S508_MAXMEM 0x40000L | ||
| 148 | |||
| 149 | /* Minimum amount of memory */ | ||
| 150 | #define S502_MINMEM 0x8000L | ||
| 151 | #define S503_MINMEM 0x8000L | ||
| 152 | #define S507_MINMEM 0x20000L | ||
| 153 | #define S508_MINMEM 0x20000L | ||
| 154 | #define NO_PORT -1 | ||
| 155 | |||
| 156 | |||
| 157 | |||
| 158 | |||
| 159 | |||
| 160 | /****** Function Prototypes *************************************************/ | ||
| 161 | |||
| 162 | /* Hardware-specific functions */ | ||
| 163 | static int sdla_detect (sdlahw_t* hw); | ||
| 164 | static int sdla_autodpm (sdlahw_t* hw); | ||
| 165 | static int sdla_setdpm (sdlahw_t* hw); | ||
| 166 | static int sdla_load (sdlahw_t* hw, sfm_t* sfm, unsigned len); | ||
| 167 | static int sdla_init (sdlahw_t* hw); | ||
| 168 | static unsigned long sdla_memtest (sdlahw_t* hw); | ||
| 169 | static int sdla_bootcfg (sdlahw_t* hw, sfm_info_t* sfminfo); | ||
| 170 | static unsigned char make_config_byte (sdlahw_t* hw); | ||
| 171 | static int sdla_start (sdlahw_t* hw, unsigned addr); | ||
| 172 | |||
| 173 | static int init_s502a (sdlahw_t* hw); | ||
| 174 | static int init_s502e (sdlahw_t* hw); | ||
| 175 | static int init_s503 (sdlahw_t* hw); | ||
| 176 | static int init_s507 (sdlahw_t* hw); | ||
| 177 | static int init_s508 (sdlahw_t* hw); | ||
| 178 | |||
| 179 | static int detect_s502a (int port); | ||
| 180 | static int detect_s502e (int port); | ||
| 181 | static int detect_s503 (int port); | ||
| 182 | static int detect_s507 (int port); | ||
| 183 | static int detect_s508 (int port); | ||
| 184 | static int detect_s514 (sdlahw_t* hw); | ||
| 185 | static int find_s514_adapter(sdlahw_t* hw, char find_first_S514_card); | ||
| 186 | |||
| 187 | /* Miscellaneous functions */ | ||
| 188 | static void peek_by_4 (unsigned long src, void* buf, unsigned len); | ||
| 189 | static void poke_by_4 (unsigned long dest, void* buf, unsigned len); | ||
| 190 | static int calibrate_delay (int mks); | ||
| 191 | static int get_option_index (unsigned* optlist, unsigned optval); | ||
| 192 | static unsigned check_memregion (void* ptr, unsigned len); | ||
| 193 | static unsigned test_memregion (void* ptr, unsigned len); | ||
| 194 | static unsigned short checksum (unsigned char* buf, unsigned len); | ||
| 195 | static int init_pci_slot(sdlahw_t *); | ||
| 196 | |||
| 197 | static int pci_probe(sdlahw_t *hw); | ||
| 198 | |||
| 199 | /****** Global Data ********************************************************** | ||
| 200 | * Note: All data must be explicitly initialized!!! | ||
| 201 | */ | ||
| 202 | |||
| 203 | static struct pci_device_id sdladrv_pci_tbl[] = { | ||
| 204 | { V3_VENDOR_ID, V3_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, }, | ||
| 205 | { } /* Terminating entry */ | ||
| 206 | }; | ||
| 207 | MODULE_DEVICE_TABLE(pci, sdladrv_pci_tbl); | ||
| 208 | |||
| 209 | MODULE_LICENSE("GPL"); | ||
| 210 | |||
| 211 | /* private data */ | ||
| 212 | static char modname[] = "sdladrv"; | ||
| 213 | static char fullname[] = "SDLA Support Module"; | ||
| 214 | static char copyright[] = "(c) 1995-1999 Sangoma Technologies Inc."; | ||
| 215 | static unsigned exec_idle; | ||
| 216 | |||
| 217 | /* Hardware configuration options. | ||
| 218 | * These are arrays of configuration options used by verification routines. | ||
| 219 | * The first element of each array is its size (i.e. number of options). | ||
| 220 | */ | ||
| 221 | static unsigned s502_port_options[] = | ||
| 222 | { 4, 0x250, 0x300, 0x350, 0x360 } | ||
| 223 | ; | ||
| 224 | static unsigned s503_port_options[] = | ||
| 225 | { 8, 0x250, 0x254, 0x300, 0x304, 0x350, 0x354, 0x360, 0x364 } | ||
| 226 | ; | ||
| 227 | static unsigned s508_port_options[] = | ||
| 228 | { 8, 0x250, 0x270, 0x280, 0x300, 0x350, 0x360, 0x380, 0x390 } | ||
| 229 | ; | ||
| 230 | |||
| 231 | static unsigned s502a_irq_options[] = { 0 }; | ||
| 232 | static unsigned s502e_irq_options[] = { 4, 2, 3, 5, 7 }; | ||
| 233 | static unsigned s503_irq_options[] = { 5, 2, 3, 4, 5, 7 }; | ||
| 234 | static unsigned s508_irq_options[] = { 8, 3, 4, 5, 7, 10, 11, 12, 15 }; | ||
| 235 | |||
| 236 | static unsigned s502a_dpmbase_options[] = | ||
| 237 | { | ||
| 238 | 28, | ||
| 239 | 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, | ||
| 240 | 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, | ||
| 241 | 0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000, | ||
| 242 | 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, | ||
| 243 | }; | ||
| 244 | static unsigned s507_dpmbase_options[] = | ||
| 245 | { | ||
| 246 | 32, | ||
| 247 | 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000, | ||
| 248 | 0xB0000, 0xB2000, 0xB4000, 0xB6000, 0xB8000, 0xBA000, 0xBC000, 0xBE000, | ||
| 249 | 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000, | ||
| 250 | 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000, | ||
| 251 | }; | ||
| 252 | static unsigned s508_dpmbase_options[] = /* incl. S502E and S503 */ | ||
| 253 | { | ||
| 254 | 32, | ||
| 255 | 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000, | ||
| 256 | 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000, | ||
| 257 | 0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000, 0xDE000, | ||
| 258 | 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000, | ||
| 259 | }; | ||
| 260 | |||
| 261 | /* | ||
| 262 | static unsigned s502_dpmsize_options[] = { 2, 0x2000, 0x10000 }; | ||
| 263 | static unsigned s507_dpmsize_options[] = { 2, 0x2000, 0x4000 }; | ||
| 264 | static unsigned s508_dpmsize_options[] = { 1, 0x2000 }; | ||
| 265 | */ | ||
| 266 | |||
| 267 | static unsigned s502a_pclk_options[] = { 2, 3600, 7200 }; | ||
| 268 | static unsigned s502e_pclk_options[] = { 5, 3600, 5000, 7200, 8000, 10000 }; | ||
| 269 | static unsigned s503_pclk_options[] = { 3, 7200, 8000, 10000 }; | ||
| 270 | static unsigned s507_pclk_options[] = { 1, 12288 }; | ||
| 271 | static unsigned s508_pclk_options[] = { 1, 16000 }; | ||
| 272 | |||
| 273 | /* Host memory control register masks */ | ||
| 274 | static unsigned char s502a_hmcr[] = | ||
| 275 | { | ||
| 276 | 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, /* A0000 - AC000 */ | ||
| 277 | 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, /* C0000 - CC000 */ | ||
| 278 | 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, /* D0000 - DC000 */ | ||
| 279 | 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, /* E0000 - EC000 */ | ||
| 280 | }; | ||
| 281 | static unsigned char s502e_hmcr[] = | ||
| 282 | { | ||
| 283 | 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E, /* A0000 - AE000 */ | ||
| 284 | 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, 0x2E, /* C0000 - CE000 */ | ||
| 285 | 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, /* D0000 - DE000 */ | ||
| 286 | 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, 0x3E, /* E0000 - EE000 */ | ||
| 287 | }; | ||
| 288 | static unsigned char s507_hmcr[] = | ||
| 289 | { | ||
| 290 | 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, /* A0000 - AE000 */ | ||
| 291 | 0x40, 0x42, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E, /* B0000 - BE000 */ | ||
| 292 | 0x80, 0x82, 0x84, 0x86, 0x88, 0x8A, 0x8C, 0x8E, /* C0000 - CE000 */ | ||
| 293 | 0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE, /* E0000 - EE000 */ | ||
| 294 | }; | ||
| 295 | static unsigned char s508_hmcr[] = | ||
| 296 | { | ||
| 297 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* A0000 - AE000 */ | ||
| 298 | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* C0000 - CE000 */ | ||
| 299 | 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* D0000 - DE000 */ | ||
| 300 | 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, /* E0000 - EE000 */ | ||
| 301 | }; | ||
| 302 | |||
| 303 | static unsigned char s507_irqmask[] = | ||
| 304 | { | ||
| 305 | 0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0 | ||
| 306 | }; | ||
| 307 | |||
| 308 | static int pci_slot_ar[MAX_S514_CARDS]; | ||
| 309 | |||
| 310 | /******* Kernel Loadable Module Entry Points ********************************/ | ||
| 311 | |||
| 312 | /*============================================================================ | ||
| 313 | * Module 'insert' entry point. | ||
| 314 | * o print announcement | ||
| 315 | * o initialize static data | ||
| 316 | * o calibrate SDLA shared memory access delay. | ||
| 317 | * | ||
| 318 | * Return: 0 Ok | ||
| 319 | * < 0 error. | ||
| 320 | * Context: process | ||
| 321 | */ | ||
| 322 | |||
| 323 | static int __init sdladrv_init(void) | ||
| 324 | { | ||
| 325 | int i=0; | ||
| 326 | |||
| 327 | printk(KERN_INFO "%s v%u.%u %s\n", | ||
| 328 | fullname, MOD_VERSION, MOD_RELEASE, copyright); | ||
| 329 | exec_idle = calibrate_delay(EXEC_DELAY); | ||
| 330 | #ifdef WANDEBUG | ||
| 331 | printk(KERN_DEBUG "%s: exec_idle = %d\n", modname, exec_idle); | ||
| 332 | #endif | ||
| 333 | |||
| 334 | /* Initialize the PCI Card array, which | ||
| 335 | * will store flags, used to mark | ||
| 336 | * card initialization state */ | ||
| 337 | for (i=0; i<MAX_S514_CARDS; i++) | ||
| 338 | pci_slot_ar[i] = 0xFF; | ||
| 339 | |||
| 340 | return 0; | ||
| 341 | } | ||
| 342 | |||
| 343 | /*============================================================================ | ||
| 344 | * Module 'remove' entry point. | ||
| 345 | * o release all remaining system resources | ||
| 346 | */ | ||
| 347 | static void __exit sdladrv_cleanup(void) | ||
| 348 | { | ||
| 349 | } | ||
| 350 | |||
| 351 | module_init(sdladrv_init); | ||
| 352 | module_exit(sdladrv_cleanup); | ||
| 353 | |||
| 354 | /******* Kernel APIs ********************************************************/ | ||
| 355 | |||
| 356 | /*============================================================================ | ||
| 357 | * Set up adapter. | ||
| 358 | * o detect adapter type | ||
| 359 | * o verify hardware configuration options | ||
| 360 | * o check for hardware conflicts | ||
| 361 | * o set up adapter shared memory | ||
| 362 | * o test adapter memory | ||
| 363 | * o load firmware | ||
| 364 | * Return: 0 ok. | ||
| 365 | * < 0 error | ||
| 366 | */ | ||
| 367 | |||
| 368 | EXPORT_SYMBOL(sdla_setup); | ||
| 369 | |||
| 370 | int sdla_setup (sdlahw_t* hw, void* sfm, unsigned len) | ||
| 371 | { | ||
| 372 | unsigned* irq_opt = NULL; /* IRQ options */ | ||
| 373 | unsigned* dpmbase_opt = NULL; /* DPM window base options */ | ||
| 374 | unsigned* pclk_opt = NULL; /* CPU clock rate options */ | ||
| 375 | int err=0; | ||
| 376 | |||
| 377 | if (sdla_detect(hw)) { | ||
| 378 | if(hw->type != SDLA_S514) | ||
| 379 | printk(KERN_INFO "%s: no SDLA card found at port 0x%X\n", | ||
| 380 | modname, hw->port); | ||
| 381 | return -EINVAL; | ||
| 382 | } | ||
| 383 | |||
| 384 | if(hw->type != SDLA_S514) { | ||
| 385 | printk(KERN_INFO "%s: found S%04u card at port 0x%X.\n", | ||
| 386 | modname, hw->type, hw->port); | ||
| 387 | |||
| 388 | hw->dpmsize = SDLA_WINDOWSIZE; | ||
| 389 | switch (hw->type) { | ||
| 390 | case SDLA_S502A: | ||
| 391 | hw->io_range = S502A_IORANGE; | ||
| 392 | irq_opt = s502a_irq_options; | ||
| 393 | dpmbase_opt = s502a_dpmbase_options; | ||
| 394 | pclk_opt = s502a_pclk_options; | ||
| 395 | break; | ||
| 396 | |||
| 397 | case SDLA_S502E: | ||
| 398 | hw->io_range = S502E_IORANGE; | ||
| 399 | irq_opt = s502e_irq_options; | ||
| 400 | dpmbase_opt = s508_dpmbase_options; | ||
| 401 | pclk_opt = s502e_pclk_options; | ||
| 402 | break; | ||
| 403 | |||
| 404 | case SDLA_S503: | ||
| 405 | hw->io_range = S503_IORANGE; | ||
| 406 | irq_opt = s503_irq_options; | ||
| 407 | dpmbase_opt = s508_dpmbase_options; | ||
| 408 | pclk_opt = s503_pclk_options; | ||
| 409 | break; | ||
| 410 | |||
| 411 | case SDLA_S507: | ||
| 412 | hw->io_range = S507_IORANGE; | ||
| 413 | irq_opt = s508_irq_options; | ||
| 414 | dpmbase_opt = s507_dpmbase_options; | ||
| 415 | pclk_opt = s507_pclk_options; | ||
| 416 | break; | ||
| 417 | |||
| 418 | case SDLA_S508: | ||
| 419 | hw->io_range = S508_IORANGE; | ||
| 420 | irq_opt = s508_irq_options; | ||
| 421 | dpmbase_opt = s508_dpmbase_options; | ||
| 422 | pclk_opt = s508_pclk_options; | ||
| 423 | break; | ||
| 424 | } | ||
| 425 | |||
| 426 | /* Verify IRQ configuration options */ | ||
| 427 | if (!get_option_index(irq_opt, hw->irq)) { | ||
| 428 | printk(KERN_INFO "%s: IRQ %d is invalid!\n", | ||
| 429 | modname, hw->irq); | ||
| 430 | return -EINVAL; | ||
| 431 | } | ||
| 432 | |||
| 433 | /* Verify CPU clock rate configuration options */ | ||
| 434 | if (hw->pclk == 0) | ||
| 435 | hw->pclk = pclk_opt[1]; /* use default */ | ||
| 436 | |||
| 437 | else if (!get_option_index(pclk_opt, hw->pclk)) { | ||
| 438 | printk(KERN_INFO "%s: CPU clock %u is invalid!\n", | ||
| 439 | modname, hw->pclk); | ||
| 440 | return -EINVAL; | ||
| 441 | } | ||
| 442 | printk(KERN_INFO "%s: assuming CPU clock rate of %u kHz.\n", | ||
| 443 | modname, hw->pclk); | ||
| 444 | |||
| 445 | /* Setup adapter dual-port memory window and test memory */ | ||
| 446 | if (hw->dpmbase == 0) { | ||
| 447 | err = sdla_autodpm(hw); | ||
| 448 | if (err) { | ||
| 449 | printk(KERN_INFO | ||
| 450 | "%s: can't find available memory region!\n", | ||
| 451 | modname); | ||
| 452 | return err; | ||
| 453 | } | ||
| 454 | } | ||
| 455 | else if (!get_option_index(dpmbase_opt, | ||
| 456 | virt_to_phys(hw->dpmbase))) { | ||
| 457 | printk(KERN_INFO | ||
| 458 | "%s: memory address 0x%lX is invalid!\n", | ||
| 459 | modname, virt_to_phys(hw->dpmbase)); | ||
| 460 | return -EINVAL; | ||
| 461 | } | ||
| 462 | else if (sdla_setdpm(hw)) { | ||
| 463 | printk(KERN_INFO | ||
| 464 | "%s: 8K memory region at 0x%lX is not available!\n", | ||
| 465 | modname, virt_to_phys(hw->dpmbase)); | ||
| 466 | return -EINVAL; | ||
| 467 | } | ||
| 468 | printk(KERN_INFO | ||
| 469 | "%s: dual-port memory window is set at 0x%lX.\n", | ||
| 470 | modname, virt_to_phys(hw->dpmbase)); | ||
| 471 | |||
| 472 | |||
| 473 | /* If we find memory in 0xE**** Memory region, | ||
| 474 | * warn the user to disable the SHADOW RAM. | ||
| 475 | * Since memory corruption can occur if SHADOW is | ||
| 476 | * enabled. This can causes random crashes ! */ | ||
| 477 | if (virt_to_phys(hw->dpmbase) >= 0xE0000){ | ||
| 478 | printk(KERN_WARNING "\n%s: !!!!!!!! WARNING !!!!!!!!\n",modname); | ||
| 479 | printk(KERN_WARNING "%s: WANPIPE is using 0x%lX memory region !!!\n", | ||
| 480 | modname, virt_to_phys(hw->dpmbase)); | ||
| 481 | printk(KERN_WARNING " Please disable the SHADOW RAM, otherwise\n"); | ||
| 482 | printk(KERN_WARNING " your system might crash randomly from time to time !\n"); | ||
| 483 | printk(KERN_WARNING "%s: !!!!!!!! WARNING !!!!!!!!\n\n",modname); | ||
| 484 | } | ||
| 485 | } | ||
| 486 | |||
| 487 | else { | ||
| 488 | hw->memory = test_memregion((void*)hw->dpmbase, | ||
| 489 | MAX_SIZEOF_S514_MEMORY); | ||
| 490 | if(hw->memory < (256 * 1024)) { | ||
| 491 | printk(KERN_INFO | ||
| 492 | "%s: error in testing S514 memory (0x%lX)\n", | ||
| 493 | modname, hw->memory); | ||
| 494 | sdla_down(hw); | ||
| 495 | return -EINVAL; | ||
| 496 | } | ||
| 497 | } | ||
| 498 | |||
| 499 | printk(KERN_INFO "%s: found %luK bytes of on-board memory\n", | ||
| 500 | modname, hw->memory / 1024); | ||
| 501 | |||
| 502 | /* Load firmware. If loader fails then shut down adapter */ | ||
| 503 | err = sdla_load(hw, sfm, len); | ||
| 504 | if (err) sdla_down(hw); /* shutdown adapter */ | ||
| 505 | |||
| 506 | return err; | ||
| 507 | } | ||
| 508 | |||
| 509 | /*============================================================================ | ||
| 510 | * Shut down SDLA: disable shared memory access and interrupts, stop CPU, etc. | ||
| 511 | */ | ||
| 512 | |||
| 513 | EXPORT_SYMBOL(sdla_down); | ||
| 514 | |||
| 515 | int sdla_down (sdlahw_t* hw) | ||
| 516 | { | ||
| 517 | unsigned port = hw->port; | ||
| 518 | int i; | ||
| 519 | unsigned char CPU_no; | ||
| 520 | u32 int_config, int_status; | ||
| 521 | |||
| 522 | if(!port && (hw->type != SDLA_S514)) | ||
| 523 | return -EFAULT; | ||
| 524 | |||
| 525 | switch (hw->type) { | ||
| 526 | case SDLA_S502A: | ||
| 527 | _OUTB(port, 0x08); /* halt CPU */ | ||
| 528 | _OUTB(port, 0x08); | ||
| 529 | _OUTB(port, 0x08); | ||
| 530 | hw->regs[0] = 0x08; | ||
| 531 | _OUTB(port + 1, 0xFF); /* close memory window */ | ||
| 532 | hw->regs[1] = 0xFF; | ||
| 533 | break; | ||
| 534 | |||
| 535 | case SDLA_S502E: | ||
| 536 | _OUTB(port + 3, 0); /* stop CPU */ | ||
| 537 | _OUTB(port, 0); /* reset board */ | ||
| 538 | for (i = 0; i < S502E_IORANGE; ++i) | ||
| 539 | hw->regs[i] = 0 | ||
| 540 | ; | ||
| 541 | break; | ||
| 542 | |||
| 543 | case SDLA_S503: | ||
| 544 | case SDLA_S507: | ||
| 545 | case SDLA_S508: | ||
| 546 | _OUTB(port, 0); /* reset board logic */ | ||
| 547 | hw->regs[0] = 0; | ||
| 548 | break; | ||
| 549 | |||
| 550 | case SDLA_S514: | ||
| 551 | /* halt the adapter */ | ||
| 552 | *(char *)hw->vector = S514_CPU_HALT; | ||
| 553 | CPU_no = hw->S514_cpu_no[0]; | ||
| 554 | |||
| 555 | /* disable the PCI IRQ and disable memory access */ | ||
| 556 | pci_read_config_dword(hw->pci_dev, PCI_INT_CONFIG, &int_config); | ||
| 557 | int_config &= (CPU_no == S514_CPU_A) ? ~PCI_DISABLE_IRQ_CPU_A : ~PCI_DISABLE_IRQ_CPU_B; | ||
| 558 | pci_write_config_dword(hw->pci_dev, PCI_INT_CONFIG, int_config); | ||
| 559 | read_S514_int_stat(hw, &int_status); | ||
| 560 | S514_intack(hw, int_status); | ||
| 561 | if(CPU_no == S514_CPU_A) | ||
| 562 | pci_write_config_dword(hw->pci_dev, PCI_MAP0_DWORD, | ||
| 563 | PCI_CPU_A_MEM_DISABLE); | ||
| 564 | else | ||
| 565 | pci_write_config_dword(hw->pci_dev, PCI_MAP1_DWORD, | ||
| 566 | PCI_CPU_B_MEM_DISABLE); | ||
| 567 | |||
| 568 | /* free up the allocated virtual memory */ | ||
| 569 | iounmap((void *)hw->dpmbase); | ||
| 570 | iounmap((void *)hw->vector); | ||
| 571 | break; | ||
| 572 | |||
| 573 | |||
| 574 | default: | ||
| 575 | return -EINVAL; | ||
| 576 | } | ||
| 577 | return 0; | ||
| 578 | } | ||
| 579 | |||
| 580 | /*============================================================================ | ||
| 581 | * Map shared memory window into SDLA address space. | ||
| 582 | */ | ||
| 583 | |||
| 584 | EXPORT_SYMBOL(sdla_mapmem); | ||
| 585 | |||
| 586 | int sdla_mapmem (sdlahw_t* hw, unsigned long addr) | ||
| 587 | { | ||
| 588 | unsigned port = hw->port; | ||
| 589 | register int tmp; | ||
| 590 | |||
| 591 | switch (hw->type) { | ||
| 592 | case SDLA_S502A: | ||
| 593 | case SDLA_S502E: | ||
| 594 | if (addr < S502_MAXMEM) { /* verify parameter */ | ||
| 595 | tmp = addr >> 13; /* convert to register mask */ | ||
| 596 | _OUTB(port + 2, tmp); | ||
| 597 | hw->regs[2] = tmp; | ||
| 598 | } | ||
| 599 | else return -EINVAL; | ||
| 600 | break; | ||
| 601 | |||
| 602 | case SDLA_S503: | ||
| 603 | if (addr < S503_MAXMEM) { /* verify parameter */ | ||
| 604 | tmp = (hw->regs[0] & 0x8F) | ((addr >> 9) & 0x70); | ||
| 605 | _OUTB(port, tmp); | ||
| 606 | hw->regs[0] = tmp; | ||
| 607 | } | ||
| 608 | else return -EINVAL; | ||
| 609 | break; | ||
| 610 | |||
| 611 | case SDLA_S507: | ||
| 612 | if (addr < S507_MAXMEM) { | ||
| 613 | if (!(_INB(port) & 0x02)) | ||
| 614 | return -EIO; | ||
| 615 | tmp = addr >> 13; /* convert to register mask */ | ||
| 616 | _OUTB(port + 2, tmp); | ||
| 617 | hw->regs[2] = tmp; | ||
| 618 | } | ||
| 619 | else return -EINVAL; | ||
| 620 | break; | ||
| 621 | |||
| 622 | case SDLA_S508: | ||
| 623 | if (addr < S508_MAXMEM) { | ||
| 624 | tmp = addr >> 13; /* convert to register mask */ | ||
| 625 | _OUTB(port + 2, tmp); | ||
| 626 | hw->regs[2] = tmp; | ||
| 627 | } | ||
| 628 | else return -EINVAL; | ||
| 629 | break; | ||
| 630 | |||
| 631 | case SDLA_S514: | ||
| 632 | return 0; | ||
| 633 | |||
| 634 | default: | ||
| 635 | return -EINVAL; | ||
| 636 | } | ||
| 637 | hw->vector = addr & 0xFFFFE000L; | ||
| 638 | return 0; | ||
| 639 | } | ||
| 640 | |||
| 641 | /*============================================================================ | ||
| 642 | * Enable interrupt generation. | ||
| 643 | */ | ||
| 644 | |||
| 645 | static int sdla_inten (sdlahw_t* hw) | ||
| 646 | { | ||
| 647 | unsigned port = hw->port; | ||
| 648 | int tmp, i; | ||
| 649 | |||
| 650 | switch (hw->type) { | ||
| 651 | case SDLA_S502E: | ||
| 652 | /* Note thar interrupt control operations on S502E are allowed | ||
| 653 | * only if CPU is enabled (bit 0 of status register is set). | ||
| 654 | */ | ||
| 655 | if (_INB(port) & 0x01) { | ||
| 656 | _OUTB(port, 0x02); /* bit1 = 1, bit2 = 0 */ | ||
| 657 | _OUTB(port, 0x06); /* bit1 = 1, bit2 = 1 */ | ||
| 658 | hw->regs[0] = 0x06; | ||
| 659 | } | ||
| 660 | else return -EIO; | ||
| 661 | break; | ||
| 662 | |||
| 663 | case SDLA_S503: | ||
| 664 | tmp = hw->regs[0] | 0x04; | ||
| 665 | _OUTB(port, tmp); | ||
| 666 | hw->regs[0] = tmp; /* update mirror */ | ||
| 667 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
| 668 | if (!(_INB(port) & 0x02)) /* verify */ | ||
| 669 | return -EIO; | ||
| 670 | break; | ||
| 671 | |||
| 672 | case SDLA_S508: | ||
| 673 | tmp = hw->regs[0] | 0x10; | ||
| 674 | _OUTB(port, tmp); | ||
| 675 | hw->regs[0] = tmp; /* update mirror */ | ||
| 676 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
| 677 | if (!(_INB(port + 1) & 0x10)) /* verify */ | ||
| 678 | return -EIO; | ||
| 679 | break; | ||
| 680 | |||
| 681 | case SDLA_S502A: | ||
| 682 | case SDLA_S507: | ||
| 683 | break; | ||
| 684 | |||
| 685 | case SDLA_S514: | ||
| 686 | break; | ||
| 687 | |||
| 688 | default: | ||
| 689 | return -EINVAL; | ||
| 690 | |||
| 691 | } | ||
| 692 | return 0; | ||
| 693 | } | ||
| 694 | |||
| 695 | /*============================================================================ | ||
| 696 | * Disable interrupt generation. | ||
| 697 | */ | ||
| 698 | |||
| 699 | #if 0 | ||
| 700 | int sdla_intde (sdlahw_t* hw) | ||
| 701 | { | ||
| 702 | unsigned port = hw->port; | ||
| 703 | int tmp, i; | ||
| 704 | |||
| 705 | switch (hw->type) { | ||
| 706 | case SDLA_S502E: | ||
| 707 | /* Notes: | ||
| 708 | * 1) interrupt control operations are allowed only if CPU is | ||
| 709 | * enabled (bit 0 of status register is set). | ||
| 710 | * 2) disabling interrupts using bit 1 of control register | ||
| 711 | * causes IRQ line go high, therefore we are going to use | ||
| 712 | * 0x04 instead: lower it to inhibit interrupts to PC. | ||
| 713 | */ | ||
| 714 | if (_INB(port) & 0x01) { | ||
| 715 | _OUTB(port, hw->regs[0] & ~0x04); | ||
| 716 | hw->regs[0] &= ~0x04; | ||
| 717 | } | ||
| 718 | else return -EIO; | ||
| 719 | break; | ||
| 720 | |||
| 721 | case SDLA_S503: | ||
| 722 | tmp = hw->regs[0] & ~0x04; | ||
| 723 | _OUTB(port, tmp); | ||
| 724 | hw->regs[0] = tmp; /* update mirror */ | ||
| 725 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
| 726 | if (_INB(port) & 0x02) /* verify */ | ||
| 727 | return -EIO; | ||
| 728 | break; | ||
| 729 | |||
| 730 | case SDLA_S508: | ||
| 731 | tmp = hw->regs[0] & ~0x10; | ||
| 732 | _OUTB(port, tmp); | ||
| 733 | hw->regs[0] = tmp; /* update mirror */ | ||
| 734 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
| 735 | if (_INB(port) & 0x10) /* verify */ | ||
| 736 | return -EIO; | ||
| 737 | break; | ||
| 738 | |||
| 739 | case SDLA_S502A: | ||
| 740 | case SDLA_S507: | ||
| 741 | break; | ||
| 742 | |||
| 743 | default: | ||
| 744 | return -EINVAL; | ||
| 745 | } | ||
| 746 | return 0; | ||
| 747 | } | ||
| 748 | #endif /* 0 */ | ||
| 749 | |||
| 750 | /*============================================================================ | ||
| 751 | * Acknowledge SDLA hardware interrupt. | ||
| 752 | */ | ||
| 753 | |||
| 754 | static int sdla_intack (sdlahw_t* hw) | ||
| 755 | { | ||
| 756 | unsigned port = hw->port; | ||
| 757 | int tmp; | ||
| 758 | |||
| 759 | switch (hw->type) { | ||
| 760 | case SDLA_S502E: | ||
| 761 | /* To acknoledge hardware interrupt we have to toggle bit 3 of | ||
| 762 | * control register: \_/ | ||
| 763 | * Note that interrupt control operations on S502E are allowed | ||
| 764 | * only if CPU is enabled (bit 1 of status register is set). | ||
| 765 | */ | ||
| 766 | if (_INB(port) & 0x01) { | ||
| 767 | tmp = hw->regs[0] & ~0x04; | ||
| 768 | _OUTB(port, tmp); | ||
| 769 | tmp |= 0x04; | ||
| 770 | _OUTB(port, tmp); | ||
| 771 | hw->regs[0] = tmp; | ||
| 772 | } | ||
| 773 | else return -EIO; | ||
| 774 | break; | ||
| 775 | |||
| 776 | case SDLA_S503: | ||
| 777 | if (_INB(port) & 0x04) { | ||
| 778 | tmp = hw->regs[0] & ~0x08; | ||
| 779 | _OUTB(port, tmp); | ||
| 780 | tmp |= 0x08; | ||
| 781 | _OUTB(port, tmp); | ||
| 782 | hw->regs[0] = tmp; | ||
| 783 | } | ||
| 784 | break; | ||
| 785 | |||
| 786 | case SDLA_S502A: | ||
| 787 | case SDLA_S507: | ||
| 788 | case SDLA_S508: | ||
| 789 | break; | ||
| 790 | |||
| 791 | default: | ||
| 792 | return -EINVAL; | ||
| 793 | } | ||
| 794 | return 0; | ||
| 795 | } | ||
| 796 | |||
| 797 | |||
| 798 | /*============================================================================ | ||
| 799 | * Acknowledge S514 hardware interrupt. | ||
| 800 | */ | ||
| 801 | |||
| 802 | EXPORT_SYMBOL(S514_intack); | ||
| 803 | |||
| 804 | void S514_intack (sdlahw_t* hw, u32 int_status) | ||
| 805 | { | ||
| 806 | pci_write_config_dword(hw->pci_dev, PCI_INT_STATUS, int_status); | ||
| 807 | } | ||
| 808 | |||
| 809 | |||
| 810 | /*============================================================================ | ||
| 811 | * Read the S514 hardware interrupt status. | ||
| 812 | */ | ||
| 813 | |||
| 814 | EXPORT_SYMBOL(read_S514_int_stat); | ||
| 815 | |||
| 816 | void read_S514_int_stat (sdlahw_t* hw, u32* int_status) | ||
| 817 | { | ||
| 818 | pci_read_config_dword(hw->pci_dev, PCI_INT_STATUS, int_status); | ||
| 819 | } | ||
| 820 | |||
| 821 | |||
| 822 | /*============================================================================ | ||
| 823 | * Generate an interrupt to adapter's CPU. | ||
| 824 | */ | ||
| 825 | |||
| 826 | #if 0 | ||
| 827 | int sdla_intr (sdlahw_t* hw) | ||
| 828 | { | ||
| 829 | unsigned port = hw->port; | ||
| 830 | |||
| 831 | switch (hw->type) { | ||
| 832 | case SDLA_S502A: | ||
| 833 | if (!(_INB(port) & 0x40)) { | ||
| 834 | _OUTB(port, 0x10); /* issue NMI to CPU */ | ||
| 835 | hw->regs[0] = 0x10; | ||
| 836 | } | ||
| 837 | else return -EIO; | ||
| 838 | break; | ||
| 839 | |||
| 840 | case SDLA_S507: | ||
| 841 | if ((_INB(port) & 0x06) == 0x06) { | ||
| 842 | _OUTB(port + 3, 0); | ||
| 843 | } | ||
| 844 | else return -EIO; | ||
| 845 | break; | ||
| 846 | |||
| 847 | case SDLA_S508: | ||
| 848 | if (_INB(port + 1) & 0x02) { | ||
| 849 | _OUTB(port, 0x08); | ||
| 850 | } | ||
| 851 | else return -EIO; | ||
| 852 | break; | ||
| 853 | |||
| 854 | case SDLA_S502E: | ||
| 855 | case SDLA_S503: | ||
| 856 | default: | ||
| 857 | return -EINVAL; | ||
| 858 | } | ||
| 859 | return 0; | ||
| 860 | } | ||
| 861 | #endif /* 0 */ | ||
| 862 | |||
| 863 | /*============================================================================ | ||
| 864 | * Execute Adapter Command. | ||
| 865 | * o Set exec flag. | ||
| 866 | * o Busy-wait until flag is reset. | ||
| 867 | * o Return number of loops made, or 0 if command timed out. | ||
| 868 | */ | ||
| 869 | |||
| 870 | EXPORT_SYMBOL(sdla_exec); | ||
| 871 | |||
| 872 | int sdla_exec (void* opflag) | ||
| 873 | { | ||
| 874 | volatile unsigned char* flag = opflag; | ||
| 875 | unsigned long tstop; | ||
| 876 | int nloops; | ||
| 877 | |||
| 878 | if(readb(flag) != 0x00) { | ||
| 879 | printk(KERN_INFO | ||
| 880 | "WANPIPE: opp flag set on entry to sdla_exec\n"); | ||
| 881 | return 0; | ||
| 882 | } | ||
| 883 | |||
| 884 | writeb(0x01, flag); | ||
| 885 | |||
| 886 | tstop = SYSTEM_TICK + EXEC_TIMEOUT; | ||
| 887 | |||
| 888 | for (nloops = 1; (readb(flag) == 0x01); ++ nloops) { | ||
| 889 | unsigned delay = exec_idle; | ||
| 890 | while (-- delay); /* delay */ | ||
| 891 | if (SYSTEM_TICK > tstop) return 0; /* time is up! */ | ||
| 892 | } | ||
| 893 | return nloops; | ||
| 894 | } | ||
| 895 | |||
| 896 | /*============================================================================ | ||
| 897 | * Read absolute adapter memory. | ||
| 898 | * Transfer data from adapter's memory to data buffer. | ||
| 899 | * | ||
| 900 | * Note: | ||
| 901 | * Care should be taken when crossing dual-port memory window boundary. | ||
| 902 | * This function is not atomic, so caller must disable interrupt if | ||
| 903 | * interrupt routines are accessing adapter shared memory. | ||
| 904 | */ | ||
| 905 | |||
| 906 | EXPORT_SYMBOL(sdla_peek); | ||
| 907 | |||
| 908 | int sdla_peek (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len) | ||
| 909 | { | ||
| 910 | |||
| 911 | if (addr + len > hw->memory) /* verify arguments */ | ||
| 912 | return -EINVAL; | ||
| 913 | |||
| 914 | if(hw->type == SDLA_S514) { /* copy data for the S514 adapter */ | ||
| 915 | peek_by_4 ((unsigned long)hw->dpmbase + addr, buf, len); | ||
| 916 | return 0; | ||
| 917 | } | ||
| 918 | |||
| 919 | else { /* copy data for the S508 adapter */ | ||
| 920 | unsigned long oldvec = hw->vector; | ||
| 921 | unsigned winsize = hw->dpmsize; | ||
| 922 | unsigned curpos, curlen; /* current offset and block size */ | ||
| 923 | unsigned long curvec; /* current DPM window vector */ | ||
| 924 | int err = 0; | ||
| 925 | |||
| 926 | while (len && !err) { | ||
| 927 | curpos = addr % winsize; /* current window offset */ | ||
| 928 | curvec = addr - curpos; /* current window vector */ | ||
| 929 | curlen = (len > (winsize - curpos)) ? | ||
| 930 | (winsize - curpos) : len; | ||
| 931 | /* Relocate window and copy block of data */ | ||
| 932 | err = sdla_mapmem(hw, curvec); | ||
| 933 | peek_by_4 ((unsigned long)hw->dpmbase + curpos, buf, | ||
| 934 | curlen); | ||
| 935 | addr += curlen; | ||
| 936 | buf = (char*)buf + curlen; | ||
| 937 | len -= curlen; | ||
| 938 | } | ||
| 939 | |||
| 940 | /* Restore DPM window position */ | ||
| 941 | sdla_mapmem(hw, oldvec); | ||
| 942 | return err; | ||
| 943 | } | ||
| 944 | } | ||
| 945 | |||
| 946 | |||
| 947 | /*============================================================================ | ||
| 948 | * Read data from adapter's memory to a data buffer in 4-byte chunks. | ||
| 949 | * Note that we ensure that the SDLA memory address is on a 4-byte boundary | ||
| 950 | * before we begin moving the data in 4-byte chunks. | ||
| 951 | */ | ||
| 952 | |||
| 953 | static void peek_by_4 (unsigned long src, void* buf, unsigned len) | ||
| 954 | { | ||
| 955 | |||
| 956 | /* byte copy data until we get to a 4-byte boundary */ | ||
| 957 | while (len && (src & 0x03)) { | ||
| 958 | *(char *)buf ++ = readb(src ++); | ||
| 959 | len --; | ||
| 960 | } | ||
| 961 | |||
| 962 | /* copy data in 4-byte chunks */ | ||
| 963 | while (len >= 4) { | ||
| 964 | *(unsigned long *)buf = readl(src); | ||
| 965 | buf += 4; | ||
| 966 | src += 4; | ||
| 967 | len -= 4; | ||
| 968 | } | ||
| 969 | |||
| 970 | /* byte copy any remaining data */ | ||
| 971 | while (len) { | ||
| 972 | *(char *)buf ++ = readb(src ++); | ||
| 973 | len --; | ||
| 974 | } | ||
| 975 | } | ||
| 976 | |||
| 977 | |||
| 978 | /*============================================================================ | ||
| 979 | * Write Absolute Adapter Memory. | ||
| 980 | * Transfer data from data buffer to adapter's memory. | ||
| 981 | * | ||
| 982 | * Note: | ||
| 983 | * Care should be taken when crossing dual-port memory window boundary. | ||
| 984 | * This function is not atomic, so caller must disable interrupt if | ||
| 985 | * interrupt routines are accessing adapter shared memory. | ||
| 986 | */ | ||
| 987 | |||
| 988 | EXPORT_SYMBOL(sdla_poke); | ||
| 989 | |||
| 990 | int sdla_poke (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len) | ||
| 991 | { | ||
| 992 | |||
| 993 | if (addr + len > hw->memory) /* verify arguments */ | ||
| 994 | return -EINVAL; | ||
| 995 | |||
| 996 | if(hw->type == SDLA_S514) { /* copy data for the S514 adapter */ | ||
| 997 | poke_by_4 ((unsigned long)hw->dpmbase + addr, buf, len); | ||
| 998 | return 0; | ||
| 999 | } | ||
| 1000 | |||
| 1001 | else { /* copy data for the S508 adapter */ | ||
| 1002 | unsigned long oldvec = hw->vector; | ||
| 1003 | unsigned winsize = hw->dpmsize; | ||
| 1004 | unsigned curpos, curlen; /* current offset and block size */ | ||
| 1005 | unsigned long curvec; /* current DPM window vector */ | ||
| 1006 | int err = 0; | ||
| 1007 | |||
| 1008 | while (len && !err) { | ||
| 1009 | curpos = addr % winsize; /* current window offset */ | ||
| 1010 | curvec = addr - curpos; /* current window vector */ | ||
| 1011 | curlen = (len > (winsize - curpos)) ? | ||
| 1012 | (winsize - curpos) : len; | ||
| 1013 | /* Relocate window and copy block of data */ | ||
| 1014 | sdla_mapmem(hw, curvec); | ||
| 1015 | poke_by_4 ((unsigned long)hw->dpmbase + curpos, buf, | ||
| 1016 | curlen); | ||
| 1017 | addr += curlen; | ||
| 1018 | buf = (char*)buf + curlen; | ||
| 1019 | len -= curlen; | ||
| 1020 | } | ||
| 1021 | |||
| 1022 | /* Restore DPM window position */ | ||
| 1023 | sdla_mapmem(hw, oldvec); | ||
| 1024 | return err; | ||
| 1025 | } | ||
| 1026 | } | ||
| 1027 | |||
| 1028 | |||
| 1029 | /*============================================================================ | ||
| 1030 | * Write from a data buffer to adapter's memory in 4-byte chunks. | ||
| 1031 | * Note that we ensure that the SDLA memory address is on a 4-byte boundary | ||
| 1032 | * before we begin moving the data in 4-byte chunks. | ||
| 1033 | */ | ||
| 1034 | |||
| 1035 | static void poke_by_4 (unsigned long dest, void* buf, unsigned len) | ||
| 1036 | { | ||
| 1037 | |||
| 1038 | /* byte copy data until we get to a 4-byte boundary */ | ||
| 1039 | while (len && (dest & 0x03)) { | ||
| 1040 | writeb (*(char *)buf ++, dest ++); | ||
| 1041 | len --; | ||
| 1042 | } | ||
| 1043 | |||
| 1044 | /* copy data in 4-byte chunks */ | ||
| 1045 | while (len >= 4) { | ||
| 1046 | writel (*(unsigned long *)buf, dest); | ||
| 1047 | dest += 4; | ||
| 1048 | buf += 4; | ||
| 1049 | len -= 4; | ||
| 1050 | } | ||
| 1051 | |||
| 1052 | /* byte copy any remaining data */ | ||
| 1053 | while (len) { | ||
| 1054 | writeb (*(char *)buf ++ , dest ++); | ||
| 1055 | len --; | ||
| 1056 | } | ||
| 1057 | } | ||
| 1058 | |||
| 1059 | |||
| 1060 | #ifdef DONT_COMPIPLE_THIS | ||
| 1061 | #endif /* DONT_COMPIPLE_THIS */ | ||
| 1062 | |||
| 1063 | /****** Hardware-Specific Functions *****************************************/ | ||
| 1064 | |||
| 1065 | /*============================================================================ | ||
| 1066 | * Detect adapter type. | ||
| 1067 | * o if adapter type is specified then call detection routine for that adapter | ||
| 1068 | * type. Otherwise call detection routines for every adapter types until | ||
| 1069 | * adapter is detected. | ||
| 1070 | * | ||
| 1071 | * Notes: | ||
| 1072 | * 1) Detection tests are destructive! Adapter will be left in shutdown state | ||
| 1073 | * after the test. | ||
| 1074 | */ | ||
| 1075 | static int sdla_detect (sdlahw_t* hw) | ||
| 1076 | { | ||
| 1077 | unsigned port = hw->port; | ||
| 1078 | int err = 0; | ||
| 1079 | |||
| 1080 | if (!port && (hw->type != SDLA_S514)) | ||
| 1081 | return -EFAULT; | ||
| 1082 | |||
| 1083 | switch (hw->type) { | ||
| 1084 | case SDLA_S502A: | ||
| 1085 | if (!detect_s502a(port)) err = -ENODEV; | ||
| 1086 | break; | ||
| 1087 | |||
| 1088 | case SDLA_S502E: | ||
| 1089 | if (!detect_s502e(port)) err = -ENODEV; | ||
| 1090 | break; | ||
| 1091 | |||
| 1092 | case SDLA_S503: | ||
| 1093 | if (!detect_s503(port)) err = -ENODEV; | ||
| 1094 | break; | ||
| 1095 | |||
| 1096 | case SDLA_S507: | ||
| 1097 | if (!detect_s507(port)) err = -ENODEV; | ||
| 1098 | break; | ||
| 1099 | |||
| 1100 | case SDLA_S508: | ||
| 1101 | if (!detect_s508(port)) err = -ENODEV; | ||
| 1102 | break; | ||
| 1103 | |||
| 1104 | case SDLA_S514: | ||
| 1105 | if (!detect_s514(hw)) err = -ENODEV; | ||
| 1106 | break; | ||
| 1107 | |||
| 1108 | default: | ||
| 1109 | if (detect_s502a(port)) | ||
| 1110 | hw->type = SDLA_S502A; | ||
| 1111 | else if (detect_s502e(port)) | ||
| 1112 | hw->type = SDLA_S502E; | ||
| 1113 | else if (detect_s503(port)) | ||
| 1114 | hw->type = SDLA_S503; | ||
| 1115 | else if (detect_s507(port)) | ||
| 1116 | hw->type = SDLA_S507; | ||
| 1117 | else if (detect_s508(port)) | ||
| 1118 | hw->type = SDLA_S508; | ||
| 1119 | else err = -ENODEV; | ||
| 1120 | } | ||
| 1121 | return err; | ||
| 1122 | } | ||
| 1123 | |||
| 1124 | /*============================================================================ | ||
| 1125 | * Autoselect memory region. | ||
| 1126 | * o try all available DMP address options from the top down until success. | ||
| 1127 | */ | ||
| 1128 | static int sdla_autodpm (sdlahw_t* hw) | ||
| 1129 | { | ||
| 1130 | int i, err = -EINVAL; | ||
| 1131 | unsigned* opt; | ||
| 1132 | |||
| 1133 | switch (hw->type) { | ||
| 1134 | case SDLA_S502A: | ||
| 1135 | opt = s502a_dpmbase_options; | ||
| 1136 | break; | ||
| 1137 | |||
| 1138 | case SDLA_S502E: | ||
| 1139 | case SDLA_S503: | ||
| 1140 | case SDLA_S508: | ||
| 1141 | opt = s508_dpmbase_options; | ||
| 1142 | break; | ||
| 1143 | |||
| 1144 | case SDLA_S507: | ||
| 1145 | opt = s507_dpmbase_options; | ||
| 1146 | break; | ||
| 1147 | |||
| 1148 | default: | ||
| 1149 | return -EINVAL; | ||
| 1150 | } | ||
| 1151 | |||
| 1152 | /* Start testing from 8th position, address | ||
| 1153 | * 0xC8000 from the 508 address table. | ||
| 1154 | * We don't want to test A**** addresses, since | ||
| 1155 | * they are usually used for Video */ | ||
| 1156 | for (i = 8; i <= opt[0] && err; i++) { | ||
| 1157 | hw->dpmbase = phys_to_virt(opt[i]); | ||
| 1158 | err = sdla_setdpm(hw); | ||
| 1159 | } | ||
| 1160 | return err; | ||
| 1161 | } | ||
| 1162 | |||
| 1163 | /*============================================================================ | ||
| 1164 | * Set up adapter dual-port memory window. | ||
| 1165 | * o shut down adapter | ||
| 1166 | * o make sure that no physical memory exists in this region, i.e entire | ||
| 1167 | * region reads 0xFF and is not writable when adapter is shut down. | ||
| 1168 | * o initialize adapter hardware | ||
| 1169 | * o make sure that region is usable with SDLA card, i.e. we can write to it | ||
| 1170 | * when adapter is configured. | ||
| 1171 | */ | ||
| 1172 | static int sdla_setdpm (sdlahw_t* hw) | ||
| 1173 | { | ||
| 1174 | int err; | ||
| 1175 | |||
| 1176 | /* Shut down card and verify memory region */ | ||
| 1177 | sdla_down(hw); | ||
| 1178 | if (check_memregion(hw->dpmbase, hw->dpmsize)) | ||
| 1179 | return -EINVAL; | ||
| 1180 | |||
| 1181 | /* Initialize adapter and test on-board memory segment by segment. | ||
| 1182 | * If memory size appears to be less than shared memory window size, | ||
| 1183 | * assume that memory region is unusable. | ||
| 1184 | */ | ||
| 1185 | err = sdla_init(hw); | ||
| 1186 | if (err) return err; | ||
| 1187 | |||
| 1188 | if (sdla_memtest(hw) < hw->dpmsize) { /* less than window size */ | ||
| 1189 | sdla_down(hw); | ||
| 1190 | return -EIO; | ||
| 1191 | } | ||
| 1192 | sdla_mapmem(hw, 0L); /* set window vector at bottom */ | ||
| 1193 | return 0; | ||
| 1194 | } | ||
| 1195 | |||
| 1196 | /*============================================================================ | ||
| 1197 | * Load adapter from the memory image of the SDLA firmware module. | ||
| 1198 | * o verify firmware integrity and compatibility | ||
| 1199 | * o start adapter up | ||
| 1200 | */ | ||
| 1201 | static int sdla_load (sdlahw_t* hw, sfm_t* sfm, unsigned len) | ||
| 1202 | { | ||
| 1203 | |||
| 1204 | int i; | ||
| 1205 | |||
| 1206 | /* Verify firmware signature */ | ||
| 1207 | if (strcmp(sfm->signature, SFM_SIGNATURE)) { | ||
| 1208 | printk(KERN_INFO "%s: not SDLA firmware!\n", | ||
| 1209 | modname); | ||
| 1210 | return -EINVAL; | ||
| 1211 | } | ||
| 1212 | |||
| 1213 | /* Verify firmware module format version */ | ||
| 1214 | if (sfm->version != SFM_VERSION) { | ||
| 1215 | printk(KERN_INFO | ||
| 1216 | "%s: firmware format %u rejected! Expecting %u.\n", | ||
| 1217 | modname, sfm->version, SFM_VERSION); | ||
| 1218 | return -EINVAL; | ||
| 1219 | } | ||
| 1220 | |||
| 1221 | /* Verify firmware module length and checksum */ | ||
| 1222 | if ((len - offsetof(sfm_t, image) != sfm->info.codesize) || | ||
| 1223 | (checksum((void*)&sfm->info, | ||
| 1224 | sizeof(sfm_info_t) + sfm->info.codesize) != sfm->checksum)) { | ||
| 1225 | printk(KERN_INFO "%s: firmware corrupted!\n", modname); | ||
| 1226 | return -EINVAL; | ||
| 1227 | } | ||
| 1228 | |||
| 1229 | /* Announce */ | ||
| 1230 | printk(KERN_INFO "%s: loading %s (ID=%u)...\n", modname, | ||
| 1231 | (sfm->descr[0] != '\0') ? sfm->descr : "unknown firmware", | ||
| 1232 | sfm->info.codeid); | ||
| 1233 | |||
| 1234 | if(hw->type == SDLA_S514) | ||
| 1235 | printk(KERN_INFO "%s: loading S514 adapter, CPU %c\n", | ||
| 1236 | modname, hw->S514_cpu_no[0]); | ||
| 1237 | |||
| 1238 | /* Scan through the list of compatible adapters and make sure our | ||
| 1239 | * adapter type is listed. | ||
| 1240 | */ | ||
| 1241 | for (i = 0; | ||
| 1242 | (i < SFM_MAX_SDLA) && (sfm->info.adapter[i] != hw->type); | ||
| 1243 | ++i); | ||
| 1244 | |||
| 1245 | if (i == SFM_MAX_SDLA) { | ||
| 1246 | printk(KERN_INFO "%s: firmware is not compatible with S%u!\n", | ||
| 1247 | modname, hw->type); | ||
| 1248 | return -EINVAL; | ||
| 1249 | } | ||
| 1250 | |||
| 1251 | |||
| 1252 | /* Make sure there is enough on-board memory */ | ||
| 1253 | if (hw->memory < sfm->info.memsize) { | ||
| 1254 | printk(KERN_INFO | ||
| 1255 | "%s: firmware needs %lu bytes of on-board memory!\n", | ||
| 1256 | modname, sfm->info.memsize); | ||
| 1257 | return -EINVAL; | ||
| 1258 | } | ||
| 1259 | |||
| 1260 | /* Move code onto adapter */ | ||
| 1261 | if (sdla_poke(hw, sfm->info.codeoffs, sfm->image, sfm->info.codesize)) { | ||
| 1262 | printk(KERN_INFO "%s: failed to load code segment!\n", | ||
| 1263 | modname); | ||
| 1264 | return -EIO; | ||
| 1265 | } | ||
| 1266 | |||
| 1267 | /* Prepare boot-time configuration data and kick-off CPU */ | ||
| 1268 | sdla_bootcfg(hw, &sfm->info); | ||
| 1269 | if (sdla_start(hw, sfm->info.startoffs)) { | ||
| 1270 | printk(KERN_INFO "%s: Damn... Adapter won't start!\n", | ||
| 1271 | modname); | ||
| 1272 | return -EIO; | ||
| 1273 | } | ||
| 1274 | |||
| 1275 | /* position DPM window over the mailbox and enable interrupts */ | ||
| 1276 | if (sdla_mapmem(hw, sfm->info.winoffs) || sdla_inten(hw)) { | ||
| 1277 | printk(KERN_INFO "%s: adapter hardware failure!\n", | ||
| 1278 | modname); | ||
| 1279 | return -EIO; | ||
| 1280 | } | ||
| 1281 | hw->fwid = sfm->info.codeid; /* set firmware ID */ | ||
| 1282 | return 0; | ||
| 1283 | } | ||
| 1284 | |||
| 1285 | /*============================================================================ | ||
| 1286 | * Initialize SDLA hardware: setup memory window, IRQ, etc. | ||
| 1287 | */ | ||
| 1288 | static int sdla_init (sdlahw_t* hw) | ||
| 1289 | { | ||
| 1290 | int i; | ||
| 1291 | |||
| 1292 | for (i = 0; i < SDLA_MAXIORANGE; ++i) | ||
| 1293 | hw->regs[i] = 0; | ||
| 1294 | |||
| 1295 | switch (hw->type) { | ||
| 1296 | case SDLA_S502A: return init_s502a(hw); | ||
| 1297 | case SDLA_S502E: return init_s502e(hw); | ||
| 1298 | case SDLA_S503: return init_s503(hw); | ||
| 1299 | case SDLA_S507: return init_s507(hw); | ||
| 1300 | case SDLA_S508: return init_s508(hw); | ||
| 1301 | } | ||
| 1302 | return -EINVAL; | ||
| 1303 | } | ||
| 1304 | |||
| 1305 | /*============================================================================ | ||
| 1306 | * Test adapter on-board memory. | ||
| 1307 | * o slide DPM window from the bottom up and test adapter memory segment by | ||
| 1308 | * segment. | ||
| 1309 | * Return adapter memory size. | ||
| 1310 | */ | ||
| 1311 | static unsigned long sdla_memtest (sdlahw_t* hw) | ||
| 1312 | { | ||
| 1313 | unsigned long memsize; | ||
| 1314 | unsigned winsize; | ||
| 1315 | |||
| 1316 | for (memsize = 0, winsize = hw->dpmsize; | ||
| 1317 | !sdla_mapmem(hw, memsize) && | ||
| 1318 | (test_memregion(hw->dpmbase, winsize) == winsize) | ||
| 1319 | ; | ||
| 1320 | memsize += winsize) | ||
| 1321 | ; | ||
| 1322 | hw->memory = memsize; | ||
| 1323 | return memsize; | ||
| 1324 | } | ||
| 1325 | |||
| 1326 | /*============================================================================ | ||
| 1327 | * Prepare boot-time firmware configuration data. | ||
| 1328 | * o position DPM window | ||
| 1329 | * o initialize configuration data area | ||
| 1330 | */ | ||
| 1331 | static int sdla_bootcfg (sdlahw_t* hw, sfm_info_t* sfminfo) | ||
| 1332 | { | ||
| 1333 | unsigned char* data; | ||
| 1334 | |||
| 1335 | if (!sfminfo->datasize) return 0; /* nothing to do */ | ||
| 1336 | |||
| 1337 | if (sdla_mapmem(hw, sfminfo->dataoffs) != 0) | ||
| 1338 | return -EIO; | ||
| 1339 | |||
| 1340 | if(hw->type == SDLA_S514) | ||
| 1341 | data = (void*)(hw->dpmbase + sfminfo->dataoffs); | ||
| 1342 | else | ||
| 1343 | data = (void*)((u8 *)hw->dpmbase + | ||
| 1344 | (sfminfo->dataoffs - hw->vector)); | ||
| 1345 | |||
| 1346 | memset_io (data, 0, sfminfo->datasize); | ||
| 1347 | |||
| 1348 | writeb (make_config_byte(hw), &data[0x00]); | ||
| 1349 | |||
| 1350 | switch (sfminfo->codeid) { | ||
| 1351 | case SFID_X25_502: | ||
| 1352 | case SFID_X25_508: | ||
| 1353 | writeb (3, &data[0x01]); /* T1 timer */ | ||
| 1354 | writeb (10, &data[0x03]); /* N2 */ | ||
| 1355 | writeb (7, &data[0x06]); /* HDLC window size */ | ||
| 1356 | writeb (1, &data[0x0B]); /* DTE */ | ||
| 1357 | writeb (2, &data[0x0C]); /* X.25 packet window size */ | ||
| 1358 | writew (128, &data[0x0D]); /* default X.25 data size */ | ||
| 1359 | writew (128, &data[0x0F]); /* maximum X.25 data size */ | ||
| 1360 | break; | ||
| 1361 | } | ||
| 1362 | return 0; | ||
| 1363 | } | ||
| 1364 | |||
| 1365 | /*============================================================================ | ||
| 1366 | * Prepare configuration byte identifying adapter type and CPU clock rate. | ||
| 1367 | */ | ||
| 1368 | static unsigned char make_config_byte (sdlahw_t* hw) | ||
| 1369 | { | ||
| 1370 | unsigned char byte = 0; | ||
| 1371 | |||
| 1372 | switch (hw->pclk) { | ||
| 1373 | case 5000: byte = 0x01; break; | ||
| 1374 | case 7200: byte = 0x02; break; | ||
| 1375 | case 8000: byte = 0x03; break; | ||
| 1376 | case 10000: byte = 0x04; break; | ||
| 1377 | case 16000: byte = 0x05; break; | ||
| 1378 | } | ||
| 1379 | |||
| 1380 | switch (hw->type) { | ||
| 1381 | case SDLA_S502E: byte |= 0x80; break; | ||
| 1382 | case SDLA_S503: byte |= 0x40; break; | ||
| 1383 | } | ||
| 1384 | return byte; | ||
| 1385 | } | ||
| 1386 | |||
| 1387 | /*============================================================================ | ||
| 1388 | * Start adapter's CPU. | ||
| 1389 | * o calculate a pointer to adapter's cold boot entry point | ||
| 1390 | * o position DPM window | ||
| 1391 | * o place boot instruction (jp addr) at cold boot entry point | ||
| 1392 | * o start CPU | ||
| 1393 | */ | ||
| 1394 | static int sdla_start (sdlahw_t* hw, unsigned addr) | ||
| 1395 | { | ||
| 1396 | unsigned port = hw->port; | ||
| 1397 | unsigned char *bootp; | ||
| 1398 | int err, tmp, i; | ||
| 1399 | |||
| 1400 | if (!port && (hw->type != SDLA_S514)) return -EFAULT; | ||
| 1401 | |||
| 1402 | switch (hw->type) { | ||
| 1403 | case SDLA_S502A: | ||
| 1404 | bootp = hw->dpmbase; | ||
| 1405 | bootp += 0x66; | ||
| 1406 | break; | ||
| 1407 | |||
| 1408 | case SDLA_S502E: | ||
| 1409 | case SDLA_S503: | ||
| 1410 | case SDLA_S507: | ||
| 1411 | case SDLA_S508: | ||
| 1412 | case SDLA_S514: | ||
| 1413 | bootp = hw->dpmbase; | ||
| 1414 | break; | ||
| 1415 | |||
| 1416 | default: | ||
| 1417 | return -EINVAL; | ||
| 1418 | } | ||
| 1419 | |||
| 1420 | err = sdla_mapmem(hw, 0); | ||
| 1421 | if (err) return err; | ||
| 1422 | |||
| 1423 | writeb (0xC3, bootp); /* Z80: 'jp' opcode */ | ||
| 1424 | bootp ++; | ||
| 1425 | writew (addr, bootp); | ||
| 1426 | |||
| 1427 | switch (hw->type) { | ||
| 1428 | case SDLA_S502A: | ||
| 1429 | _OUTB(port, 0x10); /* issue NMI to CPU */ | ||
| 1430 | hw->regs[0] = 0x10; | ||
| 1431 | break; | ||
| 1432 | |||
| 1433 | case SDLA_S502E: | ||
| 1434 | _OUTB(port + 3, 0x01); /* start CPU */ | ||
| 1435 | hw->regs[3] = 0x01; | ||
| 1436 | for (i = 0; i < SDLA_IODELAY; ++i); | ||
| 1437 | if (_INB(port) & 0x01) { /* verify */ | ||
| 1438 | /* | ||
| 1439 | * Enabling CPU changes functionality of the | ||
| 1440 | * control register, so we have to reset its | ||
| 1441 | * mirror. | ||
| 1442 | */ | ||
| 1443 | _OUTB(port, 0); /* disable interrupts */ | ||
| 1444 | hw->regs[0] = 0; | ||
| 1445 | } | ||
| 1446 | else return -EIO; | ||
| 1447 | break; | ||
| 1448 | |||
| 1449 | case SDLA_S503: | ||
| 1450 | tmp = hw->regs[0] | 0x09; /* set bits 0 and 3 */ | ||
| 1451 | _OUTB(port, tmp); | ||
| 1452 | hw->regs[0] = tmp; /* update mirror */ | ||
| 1453 | for (i = 0; i < SDLA_IODELAY; ++i); | ||
| 1454 | if (!(_INB(port) & 0x01)) /* verify */ | ||
| 1455 | return -EIO; | ||
| 1456 | break; | ||
| 1457 | |||
| 1458 | case SDLA_S507: | ||
| 1459 | tmp = hw->regs[0] | 0x02; | ||
| 1460 | _OUTB(port, tmp); | ||
| 1461 | hw->regs[0] = tmp; /* update mirror */ | ||
| 1462 | for (i = 0; i < SDLA_IODELAY; ++i); | ||
| 1463 | if (!(_INB(port) & 0x04)) /* verify */ | ||
| 1464 | return -EIO; | ||
| 1465 | break; | ||
| 1466 | |||
| 1467 | case SDLA_S508: | ||
| 1468 | tmp = hw->regs[0] | 0x02; | ||
| 1469 | _OUTB(port, tmp); | ||
| 1470 | hw->regs[0] = tmp; /* update mirror */ | ||
| 1471 | for (i = 0; i < SDLA_IODELAY; ++i); | ||
| 1472 | if (!(_INB(port + 1) & 0x02)) /* verify */ | ||
| 1473 | return -EIO; | ||
| 1474 | break; | ||
| 1475 | |||
| 1476 | case SDLA_S514: | ||
| 1477 | writeb (S514_CPU_START, hw->vector); | ||
| 1478 | break; | ||
| 1479 | |||
| 1480 | default: | ||
| 1481 | return -EINVAL; | ||
| 1482 | } | ||
| 1483 | return 0; | ||
| 1484 | } | ||
| 1485 | |||
| 1486 | /*============================================================================ | ||
| 1487 | * Initialize S502A adapter. | ||
| 1488 | */ | ||
| 1489 | static int init_s502a (sdlahw_t* hw) | ||
| 1490 | { | ||
| 1491 | unsigned port = hw->port; | ||
| 1492 | int tmp, i; | ||
| 1493 | |||
| 1494 | if (!detect_s502a(port)) | ||
| 1495 | return -ENODEV; | ||
| 1496 | |||
| 1497 | hw->regs[0] = 0x08; | ||
| 1498 | hw->regs[1] = 0xFF; | ||
| 1499 | |||
| 1500 | /* Verify configuration options */ | ||
| 1501 | i = get_option_index(s502a_dpmbase_options, virt_to_phys(hw->dpmbase)); | ||
| 1502 | if (i == 0) | ||
| 1503 | return -EINVAL; | ||
| 1504 | |||
| 1505 | tmp = s502a_hmcr[i - 1]; | ||
| 1506 | switch (hw->dpmsize) { | ||
| 1507 | case 0x2000: | ||
| 1508 | tmp |= 0x01; | ||
| 1509 | break; | ||
| 1510 | |||
| 1511 | case 0x10000L: | ||
| 1512 | break; | ||
| 1513 | |||
| 1514 | default: | ||
| 1515 | return -EINVAL; | ||
| 1516 | } | ||
| 1517 | |||
| 1518 | /* Setup dual-port memory window (this also enables memory access) */ | ||
| 1519 | _OUTB(port + 1, tmp); | ||
| 1520 | hw->regs[1] = tmp; | ||
| 1521 | hw->regs[0] = 0x08; | ||
| 1522 | return 0; | ||
| 1523 | } | ||
| 1524 | |||
| 1525 | /*============================================================================ | ||
| 1526 | * Initialize S502E adapter. | ||
| 1527 | */ | ||
| 1528 | static int init_s502e (sdlahw_t* hw) | ||
| 1529 | { | ||
| 1530 | unsigned port = hw->port; | ||
| 1531 | int tmp, i; | ||
| 1532 | |||
| 1533 | if (!detect_s502e(port)) | ||
| 1534 | return -ENODEV; | ||
| 1535 | |||
| 1536 | /* Verify configuration options */ | ||
| 1537 | i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase)); | ||
| 1538 | if (i == 0) | ||
| 1539 | return -EINVAL; | ||
| 1540 | |||
| 1541 | tmp = s502e_hmcr[i - 1]; | ||
| 1542 | switch (hw->dpmsize) { | ||
| 1543 | case 0x2000: | ||
| 1544 | tmp |= 0x01; | ||
| 1545 | break; | ||
| 1546 | |||
| 1547 | case 0x10000L: | ||
| 1548 | break; | ||
| 1549 | |||
| 1550 | default: | ||
| 1551 | return -EINVAL; | ||
| 1552 | } | ||
| 1553 | |||
| 1554 | /* Setup dual-port memory window */ | ||
| 1555 | _OUTB(port + 1, tmp); | ||
| 1556 | hw->regs[1] = tmp; | ||
| 1557 | |||
| 1558 | /* Enable memory access */ | ||
| 1559 | _OUTB(port, 0x02); | ||
| 1560 | hw->regs[0] = 0x02; | ||
| 1561 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
| 1562 | return (_INB(port) & 0x02) ? 0 : -EIO; | ||
| 1563 | } | ||
| 1564 | |||
| 1565 | /*============================================================================ | ||
| 1566 | * Initialize S503 adapter. | ||
| 1567 | * --------------------------------------------------------------------------- | ||
| 1568 | */ | ||
| 1569 | static int init_s503 (sdlahw_t* hw) | ||
| 1570 | { | ||
| 1571 | unsigned port = hw->port; | ||
| 1572 | int tmp, i; | ||
| 1573 | |||
| 1574 | if (!detect_s503(port)) | ||
| 1575 | return -ENODEV; | ||
| 1576 | |||
| 1577 | /* Verify configuration options */ | ||
| 1578 | i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase)); | ||
| 1579 | if (i == 0) | ||
| 1580 | return -EINVAL; | ||
| 1581 | |||
| 1582 | tmp = s502e_hmcr[i - 1]; | ||
| 1583 | switch (hw->dpmsize) { | ||
| 1584 | case 0x2000: | ||
| 1585 | tmp |= 0x01; | ||
| 1586 | break; | ||
| 1587 | |||
| 1588 | case 0x10000L: | ||
| 1589 | break; | ||
| 1590 | |||
| 1591 | default: | ||
| 1592 | return -EINVAL; | ||
| 1593 | } | ||
| 1594 | |||
| 1595 | /* Setup dual-port memory window */ | ||
| 1596 | _OUTB(port + 1, tmp); | ||
| 1597 | hw->regs[1] = tmp; | ||
| 1598 | |||
| 1599 | /* Enable memory access */ | ||
| 1600 | _OUTB(port, 0x02); | ||
| 1601 | hw->regs[0] = 0x02; /* update mirror */ | ||
| 1602 | return 0; | ||
| 1603 | } | ||
| 1604 | |||
| 1605 | /*============================================================================ | ||
| 1606 | * Initialize S507 adapter. | ||
| 1607 | */ | ||
| 1608 | static int init_s507 (sdlahw_t* hw) | ||
| 1609 | { | ||
| 1610 | unsigned port = hw->port; | ||
| 1611 | int tmp, i; | ||
| 1612 | |||
| 1613 | if (!detect_s507(port)) | ||
| 1614 | return -ENODEV; | ||
| 1615 | |||
| 1616 | /* Verify configuration options */ | ||
| 1617 | i = get_option_index(s507_dpmbase_options, virt_to_phys(hw->dpmbase)); | ||
| 1618 | if (i == 0) | ||
| 1619 | return -EINVAL; | ||
| 1620 | |||
| 1621 | tmp = s507_hmcr[i - 1]; | ||
| 1622 | switch (hw->dpmsize) { | ||
| 1623 | case 0x2000: | ||
| 1624 | tmp |= 0x01; | ||
| 1625 | break; | ||
| 1626 | |||
| 1627 | case 0x10000L: | ||
| 1628 | break; | ||
| 1629 | |||
| 1630 | default: | ||
| 1631 | return -EINVAL; | ||
| 1632 | } | ||
| 1633 | |||
| 1634 | /* Enable adapter's logic */ | ||
| 1635 | _OUTB(port, 0x01); | ||
| 1636 | hw->regs[0] = 0x01; | ||
| 1637 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
| 1638 | if (!(_INB(port) & 0x20)) | ||
| 1639 | return -EIO; | ||
| 1640 | |||
| 1641 | /* Setup dual-port memory window */ | ||
| 1642 | _OUTB(port + 1, tmp); | ||
| 1643 | hw->regs[1] = tmp; | ||
| 1644 | |||
| 1645 | /* Enable memory access */ | ||
| 1646 | tmp = hw->regs[0] | 0x04; | ||
| 1647 | if (hw->irq) { | ||
| 1648 | i = get_option_index(s508_irq_options, hw->irq); | ||
| 1649 | if (i) tmp |= s507_irqmask[i - 1]; | ||
| 1650 | } | ||
| 1651 | _OUTB(port, tmp); | ||
| 1652 | hw->regs[0] = tmp; /* update mirror */ | ||
| 1653 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
| 1654 | return (_INB(port) & 0x08) ? 0 : -EIO; | ||
| 1655 | } | ||
| 1656 | |||
| 1657 | /*============================================================================ | ||
| 1658 | * Initialize S508 adapter. | ||
| 1659 | */ | ||
| 1660 | static int init_s508 (sdlahw_t* hw) | ||
| 1661 | { | ||
| 1662 | unsigned port = hw->port; | ||
| 1663 | int tmp, i; | ||
| 1664 | |||
| 1665 | if (!detect_s508(port)) | ||
| 1666 | return -ENODEV; | ||
| 1667 | |||
| 1668 | /* Verify configuration options */ | ||
| 1669 | i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase)); | ||
| 1670 | if (i == 0) | ||
| 1671 | return -EINVAL; | ||
| 1672 | |||
| 1673 | /* Setup memory configuration */ | ||
| 1674 | tmp = s508_hmcr[i - 1]; | ||
| 1675 | _OUTB(port + 1, tmp); | ||
| 1676 | hw->regs[1] = tmp; | ||
| 1677 | |||
| 1678 | /* Enable memory access */ | ||
| 1679 | _OUTB(port, 0x04); | ||
| 1680 | hw->regs[0] = 0x04; /* update mirror */ | ||
| 1681 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
| 1682 | return (_INB(port + 1) & 0x04) ? 0 : -EIO; | ||
| 1683 | } | ||
| 1684 | |||
| 1685 | /*============================================================================ | ||
| 1686 | * Detect S502A adapter. | ||
| 1687 | * Following tests are used to detect S502A adapter: | ||
| 1688 | * 1. All registers other than status (BASE) should read 0xFF | ||
| 1689 | * 2. After writing 00001000b to control register, status register should | ||
| 1690 | * read 01000000b. | ||
| 1691 | * 3. After writing 0 to control register, status register should still | ||
| 1692 | * read 01000000b. | ||
| 1693 | * 4. After writing 00000100b to control register, status register should | ||
| 1694 | * read 01000100b. | ||
| 1695 | * Return 1 if detected o.k. or 0 if failed. | ||
| 1696 | * Note: This test is destructive! Adapter will be left in shutdown | ||
| 1697 | * state after the test. | ||
| 1698 | */ | ||
| 1699 | static int detect_s502a (int port) | ||
| 1700 | { | ||
| 1701 | int i, j; | ||
| 1702 | |||
| 1703 | if (!get_option_index(s502_port_options, port)) | ||
| 1704 | return 0; | ||
| 1705 | |||
| 1706 | for (j = 1; j < SDLA_MAXIORANGE; ++j) { | ||
| 1707 | if (_INB(port + j) != 0xFF) | ||
| 1708 | return 0; | ||
| 1709 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
| 1710 | } | ||
| 1711 | |||
| 1712 | _OUTB(port, 0x08); /* halt CPU */ | ||
| 1713 | _OUTB(port, 0x08); | ||
| 1714 | _OUTB(port, 0x08); | ||
| 1715 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
| 1716 | if (_INB(port) != 0x40) | ||
| 1717 | return 0; | ||
| 1718 | _OUTB(port, 0x00); | ||
| 1719 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
| 1720 | if (_INB(port) != 0x40) | ||
| 1721 | return 0; | ||
| 1722 | _OUTB(port, 0x04); | ||
| 1723 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
| 1724 | if (_INB(port) != 0x44) | ||
| 1725 | return 0; | ||
| 1726 | |||
| 1727 | /* Reset adapter */ | ||
| 1728 | _OUTB(port, 0x08); | ||
| 1729 | _OUTB(port, 0x08); | ||
| 1730 | _OUTB(port, 0x08); | ||
| 1731 | _OUTB(port + 1, 0xFF); | ||
| 1732 | return 1; | ||
| 1733 | } | ||
| 1734 | |||
| 1735 | /*============================================================================ | ||
| 1736 | * Detect S502E adapter. | ||
| 1737 | * Following tests are used to verify adapter presence: | ||
| 1738 | * 1. All registers other than status (BASE) should read 0xFF. | ||
| 1739 | * 2. After writing 0 to CPU control register (BASE+3), status register | ||
| 1740 | * (BASE) should read 11111000b. | ||
| 1741 | * 3. After writing 00000100b to port BASE (set bit 2), status register | ||
| 1742 | * (BASE) should read 11111100b. | ||
| 1743 | * Return 1 if detected o.k. or 0 if failed. | ||
| 1744 | * Note: This test is destructive! Adapter will be left in shutdown | ||
| 1745 | * state after the test. | ||
| 1746 | */ | ||
| 1747 | static int detect_s502e (int port) | ||
| 1748 | { | ||
| 1749 | int i, j; | ||
| 1750 | |||
| 1751 | if (!get_option_index(s502_port_options, port)) | ||
| 1752 | return 0; | ||
| 1753 | for (j = 1; j < SDLA_MAXIORANGE; ++j) { | ||
| 1754 | if (_INB(port + j) != 0xFF) | ||
| 1755 | return 0; | ||
| 1756 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
| 1757 | } | ||
| 1758 | |||
| 1759 | _OUTB(port + 3, 0); /* CPU control reg. */ | ||
| 1760 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
| 1761 | if (_INB(port) != 0xF8) /* read status */ | ||
| 1762 | return 0; | ||
| 1763 | _OUTB(port, 0x04); /* set bit 2 */ | ||
| 1764 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
| 1765 | if (_INB(port) != 0xFC) /* verify */ | ||
| 1766 | return 0; | ||
| 1767 | |||
| 1768 | /* Reset adapter */ | ||
| 1769 | _OUTB(port, 0); | ||
| 1770 | return 1; | ||
| 1771 | } | ||
| 1772 | |||
| 1773 | /*============================================================================ | ||
| 1774 | * Detect s503 adapter. | ||
| 1775 | * Following tests are used to verify adapter presence: | ||
| 1776 | * 1. All registers other than status (BASE) should read 0xFF. | ||
| 1777 | * 2. After writing 0 to control register (BASE), status register (BASE) | ||
| 1778 | * should read 11110000b. | ||
| 1779 | * 3. After writing 00000100b (set bit 2) to control register (BASE), | ||
| 1780 | * status register should read 11110010b. | ||
| 1781 | * Return 1 if detected o.k. or 0 if failed. | ||
| 1782 | * Note: This test is destructive! Adapter will be left in shutdown | ||
| 1783 | * state after the test. | ||
| 1784 | */ | ||
| 1785 | static int detect_s503 (int port) | ||
| 1786 | { | ||
| 1787 | int i, j; | ||
| 1788 | |||
| 1789 | if (!get_option_index(s503_port_options, port)) | ||
| 1790 | return 0; | ||
| 1791 | for (j = 1; j < SDLA_MAXIORANGE; ++j) { | ||
| 1792 | if (_INB(port + j) != 0xFF) | ||
| 1793 | return 0; | ||
| 1794 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
| 1795 | } | ||
| 1796 | |||
| 1797 | _OUTB(port, 0); /* reset control reg.*/ | ||
| 1798 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
| 1799 | if (_INB(port) != 0xF0) /* read status */ | ||
| 1800 | return 0; | ||
| 1801 | _OUTB(port, 0x04); /* set bit 2 */ | ||
| 1802 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
| 1803 | if (_INB(port) != 0xF2) /* verify */ | ||
| 1804 | return 0; | ||
| 1805 | |||
| 1806 | /* Reset adapter */ | ||
| 1807 | _OUTB(port, 0); | ||
| 1808 | return 1; | ||
| 1809 | } | ||
| 1810 | |||
| 1811 | /*============================================================================ | ||
| 1812 | * Detect s507 adapter. | ||
| 1813 | * Following tests are used to detect s507 adapter: | ||
| 1814 | * 1. All ports should read the same value. | ||
| 1815 | * 2. After writing 0x00 to control register, status register should read | ||
| 1816 | * ?011000?b. | ||
| 1817 | * 3. After writing 0x01 to control register, status register should read | ||
| 1818 | * ?011001?b. | ||
| 1819 | * Return 1 if detected o.k. or 0 if failed. | ||
| 1820 | * Note: This test is destructive! Adapter will be left in shutdown | ||
| 1821 | * state after the test. | ||
| 1822 | */ | ||
| 1823 | static int detect_s507 (int port) | ||
| 1824 | { | ||
| 1825 | int tmp, i, j; | ||
| 1826 | |||
| 1827 | if (!get_option_index(s508_port_options, port)) | ||
| 1828 | return 0; | ||
| 1829 | tmp = _INB(port); | ||
| 1830 | for (j = 1; j < S507_IORANGE; ++j) { | ||
| 1831 | if (_INB(port + j) != tmp) | ||
| 1832 | return 0; | ||
| 1833 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
| 1834 | } | ||
| 1835 | |||
| 1836 | _OUTB(port, 0x00); | ||
| 1837 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
| 1838 | if ((_INB(port) & 0x7E) != 0x30) | ||
| 1839 | return 0; | ||
| 1840 | _OUTB(port, 0x01); | ||
| 1841 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
| 1842 | if ((_INB(port) & 0x7E) != 0x32) | ||
| 1843 | return 0; | ||
| 1844 | |||
| 1845 | /* Reset adapter */ | ||
| 1846 | _OUTB(port, 0x00); | ||
| 1847 | return 1; | ||
| 1848 | } | ||
| 1849 | |||
| 1850 | /*============================================================================ | ||
| 1851 | * Detect s508 adapter. | ||
| 1852 | * Following tests are used to detect s508 adapter: | ||
| 1853 | * 1. After writing 0x00 to control register, status register should read | ||
| 1854 | * ??000000b. | ||
| 1855 | * 2. After writing 0x10 to control register, status register should read | ||
| 1856 | * ??010000b | ||
| 1857 | * Return 1 if detected o.k. or 0 if failed. | ||
| 1858 | * Note: This test is destructive! Adapter will be left in shutdown | ||
| 1859 | * state after the test. | ||
| 1860 | */ | ||
| 1861 | static int detect_s508 (int port) | ||
| 1862 | { | ||
| 1863 | int i; | ||
| 1864 | |||
| 1865 | if (!get_option_index(s508_port_options, port)) | ||
| 1866 | return 0; | ||
| 1867 | _OUTB(port, 0x00); | ||
| 1868 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
| 1869 | if ((_INB(port + 1) & 0x3F) != 0x00) | ||
| 1870 | return 0; | ||
| 1871 | _OUTB(port, 0x10); | ||
| 1872 | for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ | ||
| 1873 | if ((_INB(port + 1) & 0x3F) != 0x10) | ||
| 1874 | return 0; | ||
| 1875 | |||
| 1876 | /* Reset adapter */ | ||
| 1877 | _OUTB(port, 0x00); | ||
| 1878 | return 1; | ||
| 1879 | } | ||
| 1880 | |||
| 1881 | /*============================================================================ | ||
| 1882 | * Detect s514 PCI adapter. | ||
| 1883 | * Return 1 if detected o.k. or 0 if failed. | ||
| 1884 | * Note: This test is destructive! Adapter will be left in shutdown | ||
| 1885 | * state after the test. | ||
| 1886 | */ | ||
| 1887 | static int detect_s514 (sdlahw_t* hw) | ||
| 1888 | { | ||
| 1889 | unsigned char CPU_no, slot_no, auto_slot_cfg; | ||
| 1890 | int number_S514_cards = 0; | ||
| 1891 | u32 S514_mem_base_addr = 0; | ||
| 1892 | u32 ut_u32; | ||
| 1893 | struct pci_dev *pci_dev; | ||
| 1894 | |||
| 1895 | |||
| 1896 | #ifndef CONFIG_PCI | ||
| 1897 | printk(KERN_INFO "%s: Linux not compiled for PCI usage!\n", modname); | ||
| 1898 | return 0; | ||
| 1899 | #endif | ||
| 1900 | |||
| 1901 | /* | ||
| 1902 | The 'setup()' procedure in 'sdlamain.c' passes the CPU number and the | ||
| 1903 | slot number defined in 'router.conf' via the 'port' definition. | ||
| 1904 | */ | ||
| 1905 | CPU_no = hw->S514_cpu_no[0]; | ||
| 1906 | slot_no = hw->S514_slot_no; | ||
| 1907 | auto_slot_cfg = hw->auto_pci_cfg; | ||
| 1908 | |||
| 1909 | if (auto_slot_cfg){ | ||
| 1910 | printk(KERN_INFO "%s: srch... S514 card, CPU %c, Slot=Auto\n", | ||
| 1911 | modname, CPU_no); | ||
| 1912 | |||
| 1913 | }else{ | ||
| 1914 | printk(KERN_INFO "%s: srch... S514 card, CPU %c, Slot #%d\n", | ||
| 1915 | modname, CPU_no, slot_no); | ||
| 1916 | } | ||
| 1917 | |||
| 1918 | /* check to see that CPU A or B has been selected in 'router.conf' */ | ||
| 1919 | switch(CPU_no) { | ||
| 1920 | case S514_CPU_A: | ||
| 1921 | case S514_CPU_B: | ||
| 1922 | break; | ||
| 1923 | |||
| 1924 | default: | ||
| 1925 | printk(KERN_INFO "%s: S514 CPU definition invalid.\n", | ||
| 1926 | modname); | ||
| 1927 | printk(KERN_INFO "Must be 'A' or 'B'\n"); | ||
| 1928 | return 0; | ||
| 1929 | } | ||
| 1930 | |||
| 1931 | number_S514_cards = find_s514_adapter(hw, 0); | ||
| 1932 | if(!number_S514_cards) | ||
| 1933 | return 0; | ||
| 1934 | |||
| 1935 | /* we are using a single S514 adapter with a slot of 0 so re-read the */ | ||
| 1936 | /* location of this adapter */ | ||
| 1937 | if((number_S514_cards == 1) && auto_slot_cfg) { | ||
| 1938 | number_S514_cards = find_s514_adapter(hw, 1); | ||
| 1939 | if(!number_S514_cards) { | ||
| 1940 | printk(KERN_INFO "%s: Error finding PCI card\n", | ||
| 1941 | modname); | ||
| 1942 | return 0; | ||
| 1943 | } | ||
| 1944 | } | ||
| 1945 | |||
| 1946 | pci_dev = hw->pci_dev; | ||
| 1947 | /* read the physical memory base address */ | ||
| 1948 | S514_mem_base_addr = (CPU_no == S514_CPU_A) ? | ||
| 1949 | (pci_dev->resource[1].start) : | ||
| 1950 | (pci_dev->resource[2].start); | ||
| 1951 | |||
| 1952 | printk(KERN_INFO "%s: S514 PCI memory at 0x%X\n", | ||
| 1953 | modname, S514_mem_base_addr); | ||
| 1954 | if(!S514_mem_base_addr) { | ||
| 1955 | if(CPU_no == S514_CPU_B) | ||
| 1956 | printk(KERN_INFO "%s: CPU #B not present on the card\n", modname); | ||
| 1957 | else | ||
| 1958 | printk(KERN_INFO "%s: No PCI memory allocated to card\n", modname); | ||
| 1959 | return 0; | ||
| 1960 | } | ||
| 1961 | |||
| 1962 | /* enable the PCI memory */ | ||
| 1963 | pci_read_config_dword(pci_dev, | ||
| 1964 | (CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD, | ||
| 1965 | &ut_u32); | ||
| 1966 | pci_write_config_dword(pci_dev, | ||
| 1967 | (CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD, | ||
| 1968 | (ut_u32 | PCI_MEMORY_ENABLE)); | ||
| 1969 | |||
| 1970 | /* check the IRQ allocated and enable IRQ usage */ | ||
| 1971 | if(!(hw->irq = pci_dev->irq)) { | ||
| 1972 | printk(KERN_INFO "%s: IRQ not allocated to S514 adapter\n", | ||
| 1973 | modname); | ||
| 1974 | return 0; | ||
| 1975 | } | ||
| 1976 | |||
| 1977 | /* BUG FIX : Mar 6 2000 | ||
| 1978 | * On a initial loading of the card, we must check | ||
| 1979 | * and clear PCI interrupt bits, due to a reset | ||
| 1980 | * problem on some other boards. i.e. An interrupt | ||
| 1981 | * might be pending, even after system bootup, | ||
| 1982 | * in which case, when starting wanrouter the machine | ||
| 1983 | * would crash. | ||
| 1984 | */ | ||
| 1985 | if (init_pci_slot(hw)) | ||
| 1986 | return 0; | ||
| 1987 | |||
| 1988 | pci_read_config_dword(pci_dev, PCI_INT_CONFIG, &ut_u32); | ||
| 1989 | ut_u32 |= (CPU_no == S514_CPU_A) ? | ||
| 1990 | PCI_ENABLE_IRQ_CPU_A : PCI_ENABLE_IRQ_CPU_B; | ||
| 1991 | pci_write_config_dword(pci_dev, PCI_INT_CONFIG, ut_u32); | ||
| 1992 | |||
| 1993 | printk(KERN_INFO "%s: IRQ %d allocated to the S514 card\n", | ||
| 1994 | modname, hw->irq); | ||
| 1995 | |||
| 1996 | /* map the physical PCI memory to virtual memory */ | ||
| 1997 | hw->dpmbase = ioremap((unsigned long)S514_mem_base_addr, | ||
| 1998 | (unsigned long)MAX_SIZEOF_S514_MEMORY); | ||
| 1999 | /* map the physical control register memory to virtual memory */ | ||
| 2000 | hw->vector = (unsigned long)ioremap( | ||
| 2001 | (unsigned long)(S514_mem_base_addr + S514_CTRL_REG_BYTE), | ||
| 2002 | (unsigned long)16); | ||
| 2003 | |||
| 2004 | if(!hw->dpmbase || !hw->vector) { | ||
| 2005 | printk(KERN_INFO "%s: PCI virtual memory allocation failed\n", | ||
| 2006 | modname); | ||
| 2007 | return 0; | ||
| 2008 | } | ||
| 2009 | |||
| 2010 | /* halt the adapter */ | ||
| 2011 | writeb (S514_CPU_HALT, hw->vector); | ||
| 2012 | |||
| 2013 | return 1; | ||
| 2014 | } | ||
| 2015 | |||
| 2016 | /*============================================================================ | ||
| 2017 | * Find the S514 PCI adapter in the PCI bus. | ||
| 2018 | * Return the number of S514 adapters found (0 if no adapter found). | ||
| 2019 | */ | ||
| 2020 | static int find_s514_adapter(sdlahw_t* hw, char find_first_S514_card) | ||
| 2021 | { | ||
| 2022 | unsigned char slot_no; | ||
| 2023 | int number_S514_cards = 0; | ||
| 2024 | char S514_found_in_slot = 0; | ||
| 2025 | u16 PCI_subsys_vendor; | ||
| 2026 | |||
| 2027 | struct pci_dev *pci_dev = NULL; | ||
| 2028 | |||
| 2029 | slot_no = hw->S514_slot_no; | ||
| 2030 | |||
| 2031 | while ((pci_dev = pci_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_dev)) | ||
| 2032 | != NULL) { | ||
| 2033 | |||
| 2034 | pci_read_config_word(pci_dev, PCI_SUBSYS_VENDOR_WORD, | ||
| 2035 | &PCI_subsys_vendor); | ||
| 2036 | |||
| 2037 | if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR) | ||
| 2038 | continue; | ||
| 2039 | |||
| 2040 | hw->pci_dev = pci_dev; | ||
| 2041 | |||
| 2042 | if(find_first_S514_card) | ||
| 2043 | return(1); | ||
| 2044 | |||
| 2045 | number_S514_cards ++; | ||
| 2046 | |||
| 2047 | printk(KERN_INFO | ||
| 2048 | "%s: S514 card found, slot #%d (devfn 0x%X)\n", | ||
| 2049 | modname, ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), | ||
| 2050 | pci_dev->devfn); | ||
| 2051 | |||
| 2052 | if (hw->auto_pci_cfg){ | ||
| 2053 | hw->S514_slot_no = ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK); | ||
| 2054 | slot_no = hw->S514_slot_no; | ||
| 2055 | |||
| 2056 | }else if (((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK) == slot_no){ | ||
| 2057 | S514_found_in_slot = 1; | ||
| 2058 | break; | ||
| 2059 | } | ||
| 2060 | } | ||
| 2061 | |||
| 2062 | /* if no S514 adapter has been found, then exit */ | ||
| 2063 | if (!number_S514_cards) { | ||
| 2064 | printk(KERN_INFO "%s: Error, no S514 adapters found\n", modname); | ||
| 2065 | return 0; | ||
| 2066 | } | ||
| 2067 | /* if more than one S514 card has been found, then the user must have */ /* defined a slot number so that the correct adapter is used */ | ||
| 2068 | else if ((number_S514_cards > 1) && hw->auto_pci_cfg) { | ||
| 2069 | printk(KERN_INFO "%s: Error, PCI Slot autodetect Failed! \n" | ||
| 2070 | "%s: More than one S514 adapter found.\n" | ||
| 2071 | "%s: Disable the Autodetect feature and supply\n" | ||
| 2072 | "%s: the PCISLOT numbers for each card.\n", | ||
| 2073 | modname,modname,modname,modname); | ||
| 2074 | return 0; | ||
| 2075 | } | ||
| 2076 | /* if the user has specified a slot number and the S514 adapter has */ | ||
| 2077 | /* not been found in that slot, then exit */ | ||
| 2078 | else if (!hw->auto_pci_cfg && !S514_found_in_slot) { | ||
| 2079 | printk(KERN_INFO | ||
| 2080 | "%s: Error, S514 card not found in specified slot #%d\n", | ||
| 2081 | modname, slot_no); | ||
| 2082 | return 0; | ||
| 2083 | } | ||
| 2084 | |||
| 2085 | return (number_S514_cards); | ||
| 2086 | } | ||
| 2087 | |||
| 2088 | |||
| 2089 | |||
| 2090 | /******* Miscellaneous ******************************************************/ | ||
| 2091 | |||
| 2092 | /*============================================================================ | ||
| 2093 | * Calibrate SDLA memory access delay. | ||
| 2094 | * Count number of idle loops made within 1 second and then calculate the | ||
| 2095 | * number of loops that should be made to achive desired delay. | ||
| 2096 | */ | ||
| 2097 | static int calibrate_delay (int mks) | ||
| 2098 | { | ||
| 2099 | unsigned int delay; | ||
| 2100 | unsigned long stop; | ||
| 2101 | |||
| 2102 | for (delay = 0, stop = SYSTEM_TICK + HZ; SYSTEM_TICK < stop; ++delay); | ||
| 2103 | return (delay/(1000000L/mks) + 1); | ||
| 2104 | } | ||
| 2105 | |||
| 2106 | /*============================================================================ | ||
| 2107 | * Get option's index into the options list. | ||
| 2108 | * Return option's index (1 .. N) or zero if option is invalid. | ||
| 2109 | */ | ||
| 2110 | static int get_option_index (unsigned* optlist, unsigned optval) | ||
| 2111 | { | ||
| 2112 | int i; | ||
| 2113 | |||
| 2114 | for (i = 1; i <= optlist[0]; ++i) | ||
| 2115 | if ( optlist[i] == optval) | ||
| 2116 | return i; | ||
| 2117 | return 0; | ||
| 2118 | } | ||
| 2119 | |||
| 2120 | /*============================================================================ | ||
| 2121 | * Check memory region to see if it's available. | ||
| 2122 | * Return: 0 ok. | ||
| 2123 | */ | ||
| 2124 | static unsigned check_memregion (void* ptr, unsigned len) | ||
| 2125 | { | ||
| 2126 | volatile unsigned char* p = ptr; | ||
| 2127 | |||
| 2128 | for (; len && (readb (p) == 0xFF); --len, ++p) { | ||
| 2129 | writeb (0, p); /* attempt to write 0 */ | ||
| 2130 | if (readb(p) != 0xFF) { /* still has to read 0xFF */ | ||
| 2131 | writeb (0xFF, p);/* restore original value */ | ||
| 2132 | break; /* not good */ | ||
| 2133 | } | ||
| 2134 | } | ||
| 2135 | |||
| 2136 | return len; | ||
| 2137 | } | ||
| 2138 | |||
| 2139 | /*============================================================================ | ||
| 2140 | * Test memory region. | ||
| 2141 | * Return: size of the region that passed the test. | ||
| 2142 | * Note: Region size must be multiple of 2 ! | ||
| 2143 | */ | ||
| 2144 | static unsigned test_memregion (void* ptr, unsigned len) | ||
| 2145 | { | ||
| 2146 | volatile unsigned short* w_ptr; | ||
| 2147 | unsigned len_w = len >> 1; /* region len in words */ | ||
| 2148 | unsigned i; | ||
| 2149 | |||
| 2150 | for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) | ||
| 2151 | writew (0xAA55, w_ptr); | ||
| 2152 | |||
| 2153 | for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) | ||
| 2154 | if (readw (w_ptr) != 0xAA55) { | ||
| 2155 | len_w = i; | ||
| 2156 | break; | ||
| 2157 | } | ||
| 2158 | |||
| 2159 | for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) | ||
| 2160 | writew (0x55AA, w_ptr); | ||
| 2161 | |||
| 2162 | for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) | ||
| 2163 | if (readw(w_ptr) != 0x55AA) { | ||
| 2164 | len_w = i; | ||
| 2165 | break; | ||
| 2166 | } | ||
| 2167 | |||
| 2168 | for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) | ||
| 2169 | writew (0, w_ptr); | ||
| 2170 | |||
| 2171 | return len_w << 1; | ||
| 2172 | } | ||
| 2173 | |||
| 2174 | /*============================================================================ | ||
| 2175 | * Calculate 16-bit CRC using CCITT polynomial. | ||
| 2176 | */ | ||
| 2177 | static unsigned short checksum (unsigned char* buf, unsigned len) | ||
| 2178 | { | ||
| 2179 | unsigned short crc = 0; | ||
| 2180 | unsigned mask, flag; | ||
| 2181 | |||
| 2182 | for (; len; --len, ++buf) { | ||
| 2183 | for (mask = 0x80; mask; mask >>= 1) { | ||
| 2184 | flag = (crc & 0x8000); | ||
| 2185 | crc <<= 1; | ||
| 2186 | crc |= ((*buf & mask) ? 1 : 0); | ||
| 2187 | if (flag) crc ^= 0x1021; | ||
| 2188 | } | ||
| 2189 | } | ||
| 2190 | return crc; | ||
| 2191 | } | ||
| 2192 | |||
| 2193 | static int init_pci_slot(sdlahw_t *hw) | ||
| 2194 | { | ||
| 2195 | |||
| 2196 | u32 int_status; | ||
| 2197 | int volatile found=0; | ||
| 2198 | int i=0; | ||
| 2199 | |||
| 2200 | /* Check if this is a very first load for a specific | ||
| 2201 | * pci card. If it is, clear the interrput bits, and | ||
| 2202 | * set the flag indicating that this card was initialized. | ||
| 2203 | */ | ||
| 2204 | |||
| 2205 | for (i=0; (i<MAX_S514_CARDS) && !found; i++){ | ||
| 2206 | if (pci_slot_ar[i] == hw->S514_slot_no){ | ||
| 2207 | found=1; | ||
| 2208 | break; | ||
| 2209 | } | ||
| 2210 | if (pci_slot_ar[i] == 0xFF){ | ||
| 2211 | break; | ||
| 2212 | } | ||
| 2213 | } | ||
| 2214 | |||
| 2215 | if (!found){ | ||
| 2216 | read_S514_int_stat(hw,&int_status); | ||
| 2217 | S514_intack(hw,int_status); | ||
| 2218 | if (i == MAX_S514_CARDS){ | ||
| 2219 | printk(KERN_INFO "%s: Critical Error !!!\n",modname); | ||
| 2220 | printk(KERN_INFO | ||
| 2221 | "%s: Number of Sangoma PCI cards exceeded maximum limit.\n", | ||
| 2222 | modname); | ||
| 2223 | printk(KERN_INFO "Please contact Sangoma Technologies\n"); | ||
| 2224 | return 1; | ||
| 2225 | } | ||
| 2226 | pci_slot_ar[i] = hw->S514_slot_no; | ||
| 2227 | } | ||
| 2228 | return 0; | ||
| 2229 | } | ||
| 2230 | |||
| 2231 | static int pci_probe(sdlahw_t *hw) | ||
| 2232 | { | ||
| 2233 | |||
| 2234 | unsigned char slot_no; | ||
| 2235 | int number_S514_cards = 0; | ||
| 2236 | u16 PCI_subsys_vendor; | ||
| 2237 | u16 PCI_card_type; | ||
| 2238 | |||
| 2239 | struct pci_dev *pci_dev = NULL; | ||
| 2240 | struct pci_bus *bus = NULL; | ||
| 2241 | |||
| 2242 | slot_no = 0; | ||
| 2243 | |||
| 2244 | while ((pci_dev = pci_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_dev)) | ||
| 2245 | != NULL) { | ||
| 2246 | |||
| 2247 | pci_read_config_word(pci_dev, PCI_SUBSYS_VENDOR_WORD, | ||
| 2248 | &PCI_subsys_vendor); | ||
| 2249 | |||
| 2250 | if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR) | ||
| 2251 | continue; | ||
| 2252 | |||
| 2253 | pci_read_config_word(pci_dev, PCI_CARD_TYPE, | ||
| 2254 | &PCI_card_type); | ||
| 2255 | |||
| 2256 | bus = pci_dev->bus; | ||
| 2257 | |||
| 2258 | /* A dual cpu card can support up to 4 physical connections, | ||
| 2259 | * where a single cpu card can support up to 2 physical | ||
| 2260 | * connections. The FT1 card can only support a single | ||
| 2261 | * connection, however we cannot distinguish between a Single | ||
| 2262 | * CPU card and an FT1 card. */ | ||
| 2263 | if (PCI_card_type == S514_DUAL_CPU){ | ||
| 2264 | number_S514_cards += 4; | ||
| 2265 | printk(KERN_INFO | ||
| 2266 | "wanpipe: S514-PCI card found, cpu(s) 2, bus #%d, slot #%d, irq #%d\n", | ||
| 2267 | bus->number,((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), | ||
| 2268 | pci_dev->irq); | ||
| 2269 | }else{ | ||
| 2270 | number_S514_cards += 2; | ||
| 2271 | printk(KERN_INFO | ||
| 2272 | "wanpipe: S514-PCI card found, cpu(s) 1, bus #%d, slot #%d, irq #%d\n", | ||
| 2273 | bus->number,((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), | ||
| 2274 | pci_dev->irq); | ||
| 2275 | } | ||
| 2276 | } | ||
| 2277 | |||
| 2278 | return number_S514_cards; | ||
| 2279 | |||
| 2280 | } | ||
| 2281 | |||
| 2282 | |||
| 2283 | |||
| 2284 | EXPORT_SYMBOL(wanpipe_hw_probe); | ||
| 2285 | |||
| 2286 | unsigned wanpipe_hw_probe(void) | ||
| 2287 | { | ||
| 2288 | sdlahw_t hw; | ||
| 2289 | unsigned* opt = s508_port_options; | ||
| 2290 | unsigned cardno=0; | ||
| 2291 | int i; | ||
| 2292 | |||
| 2293 | memset(&hw, 0, sizeof(hw)); | ||
| 2294 | |||
| 2295 | for (i = 1; i <= opt[0]; i++) { | ||
| 2296 | if (detect_s508(opt[i])){ | ||
| 2297 | /* S508 card can support up to two physical links */ | ||
| 2298 | cardno+=2; | ||
| 2299 | printk(KERN_INFO "wanpipe: S508-ISA card found, port 0x%x\n",opt[i]); | ||
| 2300 | } | ||
| 2301 | } | ||
| 2302 | |||
| 2303 | #ifdef CONFIG_PCI | ||
| 2304 | hw.S514_slot_no = 0; | ||
| 2305 | cardno += pci_probe(&hw); | ||
| 2306 | #else | ||
| 2307 | printk(KERN_INFO "wanpipe: Warning, Kernel not compiled for PCI support!\n"); | ||
| 2308 | printk(KERN_INFO "wanpipe: PCI Hardware Probe Failed!\n"); | ||
| 2309 | #endif | ||
| 2310 | |||
| 2311 | return cardno; | ||
| 2312 | } | ||
| 2313 | |||
| 2314 | /****** End *****************************************************************/ | ||
diff --git a/drivers/net/wan/sdlamain.c b/drivers/net/wan/sdlamain.c deleted file mode 100644 index 7a8b22a7ea31..000000000000 --- a/drivers/net/wan/sdlamain.c +++ /dev/null | |||
| @@ -1,1346 +0,0 @@ | |||
| 1 | /**************************************************************************** | ||
| 2 | * sdlamain.c WANPIPE(tm) Multiprotocol WAN Link Driver. Main module. | ||
| 3 | * | ||
| 4 | * Author: Nenad Corbic <ncorbic@sangoma.com> | ||
| 5 | * Gideon Hack | ||
| 6 | * | ||
| 7 | * Copyright: (c) 1995-2000 Sangoma Technologies Inc. | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or | ||
| 10 | * modify it under the terms of the GNU General Public License | ||
| 11 | * as published by the Free Software Foundation; either version | ||
| 12 | * 2 of the License, or (at your option) any later version. | ||
| 13 | * ============================================================================ | ||
| 14 | * Dec 22, 2000 Nenad Corbic Updated for 2.4.X kernels. | ||
| 15 | * Removed the polling routine. | ||
| 16 | * Nov 13, 2000 Nenad Corbic Added hw probing on module load and dynamic | ||
| 17 | * device allocation. | ||
| 18 | * Nov 7, 2000 Nenad Corbic Fixed the Multi-Port PPP for kernels | ||
| 19 | * 2.2.16 and above. | ||
| 20 | * Aug 2, 2000 Nenad Corbic Block the Multi-Port PPP from running on | ||
| 21 | * kernels 2.2.16 or greater. The SyncPPP | ||
| 22 | * has changed. | ||
| 23 | * Jul 25, 2000 Nenad Corbic Updated the Piggiback support for MultPPPP. | ||
| 24 | * Jul 13, 2000 Nenad Corbic Added Multi-PPP support. | ||
| 25 | * Feb 02, 2000 Nenad Corbic Fixed up piggyback probing and selection. | ||
| 26 | * Sep 23, 1999 Nenad Corbic Added support for SMP | ||
| 27 | * Sep 13, 1999 Nenad Corbic Each port is treated as a separate device. | ||
| 28 | * Jun 02, 1999 Gideon Hack Added support for the S514 adapter. | ||
| 29 | * Updates for Linux 2.2.X kernels. | ||
| 30 | * Sep 17, 1998 Jaspreet Singh Updated for 2.1.121+ kernel | ||
| 31 | * Nov 28, 1997 Jaspreet Singh Changed DRV_RELEASE to 1 | ||
| 32 | * Nov 10, 1997 Jaspreet Singh Changed sti() to restore_flags(); | ||
| 33 | * Nov 06, 1997 Jaspreet Singh Changed DRV_VERSION to 4 and DRV_RELEASE to 0 | ||
| 34 | * Oct 20, 1997 Jaspreet Singh Modified sdla_isr routine so that card->in_isr | ||
| 35 | * assignments are taken out and placed in the | ||
| 36 | * sdla_ppp.c, sdla_fr.c and sdla_x25.c isr | ||
| 37 | * routines. Took out 'wandev->tx_int_enabled' and | ||
| 38 | * replaced it with 'wandev->enable_tx_int'. | ||
| 39 | * May 29, 1997 Jaspreet Singh Flow Control Problem | ||
| 40 | * added "wandev->tx_int_enabled=1" line in the | ||
| 41 | * init module. This line initializes the flag for | ||
| 42 | * preventing Interrupt disabled with device set to | ||
| 43 | * busy | ||
| 44 | * Jan 15, 1997 Gene Kozin Version 3.1.0 | ||
| 45 | * o added UDP management stuff | ||
| 46 | * Jan 02, 1997 Gene Kozin Initial version. | ||
| 47 | *****************************************************************************/ | ||
| 48 | |||
| 49 | #include <linux/config.h> /* OS configuration options */ | ||
| 50 | #include <linux/stddef.h> /* offsetof(), etc. */ | ||
| 51 | #include <linux/errno.h> /* return codes */ | ||
| 52 | #include <linux/string.h> /* inline memset(), etc. */ | ||
| 53 | #include <linux/init.h> | ||
| 54 | #include <linux/slab.h> /* kmalloc(), kfree() */ | ||
| 55 | #include <linux/kernel.h> /* printk(), and other useful stuff */ | ||
| 56 | #include <linux/module.h> /* support for loadable modules */ | ||
| 57 | #include <linux/ioport.h> /* request_region(), release_region() */ | ||
| 58 | #include <linux/wanrouter.h> /* WAN router definitions */ | ||
| 59 | #include <linux/wanpipe.h> /* WANPIPE common user API definitions */ | ||
| 60 | #include <linux/rcupdate.h> | ||
| 61 | |||
| 62 | #include <linux/in.h> | ||
| 63 | #include <asm/io.h> /* phys_to_virt() */ | ||
| 64 | #include <linux/pci.h> | ||
| 65 | #include <linux/sdlapci.h> | ||
| 66 | #include <linux/if_wanpipe_common.h> | ||
| 67 | |||
| 68 | #include <asm/uaccess.h> /* kernel <-> user copy */ | ||
| 69 | #include <linux/inetdevice.h> | ||
| 70 | |||
| 71 | #include <linux/ip.h> | ||
| 72 | #include <net/route.h> | ||
| 73 | |||
| 74 | #define KMEM_SAFETYZONE 8 | ||
| 75 | |||
| 76 | |||
| 77 | #ifndef CONFIG_WANPIPE_FR | ||
| 78 | #define wpf_init(a,b) (-EPROTONOSUPPORT) | ||
| 79 | #endif | ||
| 80 | |||
| 81 | #ifndef CONFIG_WANPIPE_CHDLC | ||
| 82 | #define wpc_init(a,b) (-EPROTONOSUPPORT) | ||
| 83 | #endif | ||
| 84 | |||
| 85 | #ifndef CONFIG_WANPIPE_X25 | ||
| 86 | #define wpx_init(a,b) (-EPROTONOSUPPORT) | ||
| 87 | #endif | ||
| 88 | |||
| 89 | #ifndef CONFIG_WANPIPE_PPP | ||
| 90 | #define wpp_init(a,b) (-EPROTONOSUPPORT) | ||
| 91 | #endif | ||
| 92 | |||
| 93 | #ifndef CONFIG_WANPIPE_MULTPPP | ||
| 94 | #define wsppp_init(a,b) (-EPROTONOSUPPORT) | ||
| 95 | #endif | ||
| 96 | |||
| 97 | |||
| 98 | /***********FOR DEBUGGING PURPOSES********************************************* | ||
| 99 | static void * dbg_kmalloc(unsigned int size, int prio, int line) { | ||
| 100 | int i = 0; | ||
| 101 | void * v = kmalloc(size+sizeof(unsigned int)+2*KMEM_SAFETYZONE*8,prio); | ||
| 102 | char * c1 = v; | ||
| 103 | c1 += sizeof(unsigned int); | ||
| 104 | *((unsigned int *)v) = size; | ||
| 105 | |||
| 106 | for (i = 0; i < KMEM_SAFETYZONE; i++) { | ||
| 107 | c1[0] = 'D'; c1[1] = 'E'; c1[2] = 'A'; c1[3] = 'D'; | ||
| 108 | c1[4] = 'B'; c1[5] = 'E'; c1[6] = 'E'; c1[7] = 'F'; | ||
| 109 | c1 += 8; | ||
| 110 | } | ||
| 111 | c1 += size; | ||
| 112 | for (i = 0; i < KMEM_SAFETYZONE; i++) { | ||
| 113 | c1[0] = 'M'; c1[1] = 'U'; c1[2] = 'N'; c1[3] = 'G'; | ||
| 114 | c1[4] = 'W'; c1[5] = 'A'; c1[6] = 'L'; c1[7] = 'L'; | ||
| 115 | c1 += 8; | ||
| 116 | } | ||
| 117 | v = ((char *)v) + sizeof(unsigned int) + KMEM_SAFETYZONE*8; | ||
| 118 | printk(KERN_INFO "line %d kmalloc(%d,%d) = %p\n",line,size,prio,v); | ||
| 119 | return v; | ||
| 120 | } | ||
| 121 | static void dbg_kfree(void * v, int line) { | ||
| 122 | unsigned int * sp = (unsigned int *)(((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8)); | ||
| 123 | unsigned int size = *sp; | ||
| 124 | char * c1 = ((char *)v) - KMEM_SAFETYZONE*8; | ||
| 125 | int i = 0; | ||
| 126 | for (i = 0; i < KMEM_SAFETYZONE; i++) { | ||
| 127 | if ( c1[0] != 'D' || c1[1] != 'E' || c1[2] != 'A' || c1[3] != 'D' | ||
| 128 | || c1[4] != 'B' || c1[5] != 'E' || c1[6] != 'E' || c1[7] != 'F') { | ||
| 129 | printk(KERN_INFO "kmalloced block at %p has been corrupted (underrun)!\n",v); | ||
| 130 | printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, | ||
| 131 | c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); | ||
| 132 | } | ||
| 133 | c1 += 8; | ||
| 134 | } | ||
| 135 | c1 += size; | ||
| 136 | for (i = 0; i < KMEM_SAFETYZONE; i++) { | ||
| 137 | if ( c1[0] != 'M' || c1[1] != 'U' || c1[2] != 'N' || c1[3] != 'G' | ||
| 138 | || c1[4] != 'W' || c1[5] != 'A' || c1[6] != 'L' || c1[7] != 'L' | ||
| 139 | ) { | ||
| 140 | printk(KERN_INFO "kmalloced block at %p has been corrupted (overrun):\n",v); | ||
| 141 | printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, | ||
| 142 | c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); | ||
| 143 | } | ||
| 144 | c1 += 8; | ||
| 145 | } | ||
| 146 | printk(KERN_INFO "line %d kfree(%p)\n",line,v); | ||
| 147 | v = ((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8); | ||
| 148 | kfree(v); | ||
| 149 | } | ||
| 150 | |||
| 151 | #define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__) | ||
| 152 | #define kfree(x) dbg_kfree(x,__LINE__) | ||
| 153 | ******************************************************************************/ | ||
| 154 | |||
| 155 | |||
| 156 | |||
| 157 | /****** Defines & Macros ****************************************************/ | ||
| 158 | |||
| 159 | #ifdef _DEBUG_ | ||
| 160 | #define STATIC | ||
| 161 | #else | ||
| 162 | #define STATIC static | ||
| 163 | #endif | ||
| 164 | |||
| 165 | #define DRV_VERSION 5 /* version number */ | ||
| 166 | #define DRV_RELEASE 0 /* release (minor version) number */ | ||
| 167 | #define MAX_CARDS 16 /* max number of adapters */ | ||
| 168 | |||
| 169 | #ifndef CONFIG_WANPIPE_CARDS /* configurable option */ | ||
| 170 | #define CONFIG_WANPIPE_CARDS 1 | ||
| 171 | #endif | ||
| 172 | |||
| 173 | #define CMD_OK 0 /* normal firmware return code */ | ||
| 174 | #define CMD_TIMEOUT 0xFF /* firmware command timed out */ | ||
| 175 | #define MAX_CMD_RETRY 10 /* max number of firmware retries */ | ||
| 176 | /****** Function Prototypes *************************************************/ | ||
| 177 | |||
| 178 | extern void disable_irq(unsigned int); | ||
| 179 | extern void enable_irq(unsigned int); | ||
| 180 | |||
| 181 | /* WAN link driver entry points */ | ||
| 182 | static int setup(struct wan_device* wandev, wandev_conf_t* conf); | ||
| 183 | static int shutdown(struct wan_device* wandev); | ||
| 184 | static int ioctl(struct wan_device* wandev, unsigned cmd, unsigned long arg); | ||
| 185 | |||
| 186 | /* IOCTL handlers */ | ||
| 187 | static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump); | ||
| 188 | static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec, int); | ||
| 189 | |||
| 190 | /* Miscellaneous functions */ | ||
| 191 | STATIC irqreturn_t sdla_isr (int irq, void* dev_id, struct pt_regs *regs); | ||
| 192 | static void release_hw (sdla_t *card); | ||
| 193 | |||
| 194 | static int check_s508_conflicts (sdla_t* card,wandev_conf_t* conf, int*); | ||
| 195 | static int check_s514_conflicts (sdla_t* card,wandev_conf_t* conf, int*); | ||
| 196 | |||
| 197 | |||
| 198 | /****** Global Data ********************************************************** | ||
| 199 | * Note: All data must be explicitly initialized!!! | ||
| 200 | */ | ||
| 201 | |||
| 202 | /* private data */ | ||
| 203 | static char drvname[] = "wanpipe"; | ||
| 204 | static char fullname[] = "WANPIPE(tm) Multiprotocol Driver"; | ||
| 205 | static char copyright[] = "(c) 1995-2000 Sangoma Technologies Inc."; | ||
| 206 | static int ncards; | ||
| 207 | static sdla_t* card_array; /* adapter data space */ | ||
| 208 | |||
| 209 | /* Wanpipe's own workqueue, used for all API's. | ||
| 210 | * All protocol specific tasks will be inserted | ||
| 211 | * into the "wanpipe_wq" workqueue. | ||
| 212 | |||
| 213 | * The kernel workqueue mechanism will execute | ||
| 214 | * all pending tasks in the "wanpipe_wq" workqueue. | ||
| 215 | */ | ||
| 216 | |||
| 217 | struct workqueue_struct *wanpipe_wq; | ||
| 218 | DECLARE_WORK(wanpipe_work, NULL, NULL); | ||
| 219 | |||
| 220 | static int wanpipe_bh_critical; | ||
| 221 | |||
| 222 | /******* Kernel Loadable Module Entry Points ********************************/ | ||
| 223 | |||
| 224 | /*============================================================================ | ||
| 225 | * Module 'insert' entry point. | ||
| 226 | * o print announcement | ||
| 227 | * o allocate adapter data space | ||
| 228 | * o initialize static data | ||
| 229 | * o register all cards with WAN router | ||
| 230 | * o calibrate SDLA shared memory access delay. | ||
| 231 | * | ||
| 232 | * Return: 0 Ok | ||
| 233 | * < 0 error. | ||
| 234 | * Context: process | ||
| 235 | */ | ||
| 236 | |||
| 237 | static int __init wanpipe_init(void) | ||
| 238 | { | ||
| 239 | int cnt, err = 0; | ||
| 240 | |||
| 241 | printk(KERN_INFO "%s v%u.%u %s\n", | ||
| 242 | fullname, DRV_VERSION, DRV_RELEASE, copyright); | ||
| 243 | |||
| 244 | wanpipe_wq = create_workqueue("wanpipe_wq"); | ||
| 245 | if (!wanpipe_wq) | ||
| 246 | return -ENOMEM; | ||
| 247 | |||
| 248 | /* Probe for wanpipe cards and return the number found */ | ||
| 249 | printk(KERN_INFO "wanpipe: Probing for WANPIPE hardware.\n"); | ||
| 250 | ncards = wanpipe_hw_probe(); | ||
| 251 | if (ncards){ | ||
| 252 | printk(KERN_INFO "wanpipe: Allocating maximum %i devices: wanpipe%i - wanpipe%i.\n",ncards,1,ncards); | ||
| 253 | }else{ | ||
| 254 | printk(KERN_INFO "wanpipe: No S514/S508 cards found, unloading modules!\n"); | ||
| 255 | destroy_workqueue(wanpipe_wq); | ||
| 256 | return -ENODEV; | ||
| 257 | } | ||
| 258 | |||
| 259 | /* Verify number of cards and allocate adapter data space */ | ||
| 260 | card_array = kmalloc(sizeof(sdla_t) * ncards, GFP_KERNEL); | ||
| 261 | if (card_array == NULL) { | ||
| 262 | destroy_workqueue(wanpipe_wq); | ||
| 263 | return -ENOMEM; | ||
| 264 | } | ||
| 265 | |||
| 266 | memset(card_array, 0, sizeof(sdla_t) * ncards); | ||
| 267 | |||
| 268 | /* Register adapters with WAN router */ | ||
| 269 | for (cnt = 0; cnt < ncards; ++ cnt) { | ||
| 270 | sdla_t* card = &card_array[cnt]; | ||
| 271 | struct wan_device* wandev = &card->wandev; | ||
| 272 | |||
| 273 | card->next = NULL; | ||
| 274 | sprintf(card->devname, "%s%d", drvname, cnt + 1); | ||
| 275 | wandev->magic = ROUTER_MAGIC; | ||
| 276 | wandev->name = card->devname; | ||
| 277 | wandev->private = card; | ||
| 278 | wandev->enable_tx_int = 0; | ||
| 279 | wandev->setup = &setup; | ||
| 280 | wandev->shutdown = &shutdown; | ||
| 281 | wandev->ioctl = &ioctl; | ||
| 282 | err = register_wan_device(wandev); | ||
| 283 | if (err) { | ||
| 284 | printk(KERN_INFO | ||
| 285 | "%s: %s registration failed with error %d!\n", | ||
| 286 | drvname, card->devname, err); | ||
| 287 | break; | ||
| 288 | } | ||
| 289 | } | ||
| 290 | if (cnt){ | ||
| 291 | ncards = cnt; /* adjust actual number of cards */ | ||
| 292 | }else { | ||
| 293 | kfree(card_array); | ||
| 294 | destroy_workqueue(wanpipe_wq); | ||
| 295 | printk(KERN_INFO "IN Init Module: NO Cards registered\n"); | ||
| 296 | err = -ENODEV; | ||
| 297 | } | ||
| 298 | |||
| 299 | return err; | ||
| 300 | } | ||
| 301 | |||
| 302 | /*============================================================================ | ||
| 303 | * Module 'remove' entry point. | ||
| 304 | * o unregister all adapters from the WAN router | ||
| 305 | * o release all remaining system resources | ||
| 306 | */ | ||
| 307 | static void __exit wanpipe_cleanup(void) | ||
| 308 | { | ||
| 309 | int i; | ||
| 310 | |||
| 311 | if (!ncards) | ||
| 312 | return; | ||
| 313 | |||
| 314 | for (i = 0; i < ncards; ++i) { | ||
| 315 | sdla_t* card = &card_array[i]; | ||
| 316 | unregister_wan_device(card->devname); | ||
| 317 | } | ||
| 318 | destroy_workqueue(wanpipe_wq); | ||
| 319 | kfree(card_array); | ||
| 320 | |||
| 321 | printk(KERN_INFO "\nwanpipe: WANPIPE Modules Unloaded.\n"); | ||
| 322 | } | ||
| 323 | |||
| 324 | module_init(wanpipe_init); | ||
| 325 | module_exit(wanpipe_cleanup); | ||
| 326 | |||
| 327 | /******* WAN Device Driver Entry Points *************************************/ | ||
| 328 | |||
| 329 | /*============================================================================ | ||
| 330 | * Setup/configure WAN link driver. | ||
| 331 | * o check adapter state | ||
| 332 | * o make sure firmware is present in configuration | ||
| 333 | * o make sure I/O port and IRQ are specified | ||
| 334 | * o make sure I/O region is available | ||
| 335 | * o allocate interrupt vector | ||
| 336 | * o setup SDLA hardware | ||
| 337 | * o call appropriate routine to perform protocol-specific initialization | ||
| 338 | * o mark I/O region as used | ||
| 339 | * o if this is the first active card, then schedule background task | ||
| 340 | * | ||
| 341 | * This function is called when router handles ROUTER_SETUP IOCTL. The | ||
| 342 | * configuration structure is in kernel memory (including extended data, if | ||
| 343 | * any). | ||
| 344 | */ | ||
| 345 | |||
| 346 | static int setup(struct wan_device* wandev, wandev_conf_t* conf) | ||
| 347 | { | ||
| 348 | sdla_t* card; | ||
| 349 | int err = 0; | ||
| 350 | int irq=0; | ||
| 351 | |||
| 352 | /* Sanity checks */ | ||
| 353 | if ((wandev == NULL) || (wandev->private == NULL) || (conf == NULL)){ | ||
| 354 | printk(KERN_INFO | ||
| 355 | "%s: Failed Sdlamain Setup wandev %u, card %u, conf %u !\n", | ||
| 356 | wandev->name, | ||
| 357 | (unsigned int)wandev,(unsigned int)wandev->private, | ||
| 358 | (unsigned int)conf); | ||
| 359 | return -EFAULT; | ||
| 360 | } | ||
| 361 | |||
| 362 | printk(KERN_INFO "%s: Starting WAN Setup\n", wandev->name); | ||
| 363 | |||
| 364 | card = wandev->private; | ||
| 365 | if (wandev->state != WAN_UNCONFIGURED){ | ||
| 366 | printk(KERN_INFO "%s: failed sdlamain setup, busy!\n", | ||
| 367 | wandev->name); | ||
| 368 | return -EBUSY; /* already configured */ | ||
| 369 | } | ||
| 370 | |||
| 371 | printk(KERN_INFO "\nProcessing WAN device %s...\n", wandev->name); | ||
| 372 | |||
| 373 | /* Initialize the counters for each wandev | ||
| 374 | * Used for counting number of times new_if and | ||
| 375 | * del_if get called. | ||
| 376 | */ | ||
| 377 | wandev->del_if_cnt = 0; | ||
| 378 | wandev->new_if_cnt = 0; | ||
| 379 | wandev->config_id = conf->config_id; | ||
| 380 | |||
| 381 | if (!conf->data_size || (conf->data == NULL)) { | ||
| 382 | printk(KERN_INFO | ||
| 383 | "%s: firmware not found in configuration data!\n", | ||
| 384 | wandev->name); | ||
| 385 | return -EINVAL; | ||
| 386 | } | ||
| 387 | |||
| 388 | /* Check for resource conflicts and setup the | ||
| 389 | * card for piggibacking if necessary */ | ||
| 390 | if(!conf->S514_CPU_no[0]) { | ||
| 391 | if ((err=check_s508_conflicts(card,conf,&irq)) != 0){ | ||
| 392 | return err; | ||
| 393 | } | ||
| 394 | }else { | ||
| 395 | if ((err=check_s514_conflicts(card,conf,&irq)) != 0){ | ||
| 396 | return err; | ||
| 397 | } | ||
| 398 | } | ||
| 399 | |||
| 400 | /* If the current card has already been configured | ||
| 401 | * or it's a piggyback card, do not try to allocate | ||
| 402 | * resources. | ||
| 403 | */ | ||
| 404 | if (!card->wandev.piggyback && !card->configured){ | ||
| 405 | |||
| 406 | /* Configure hardware, load firmware, etc. */ | ||
| 407 | memset(&card->hw, 0, sizeof(sdlahw_t)); | ||
| 408 | |||
| 409 | /* for an S514 adapter, pass the CPU number and the slot number read */ | ||
| 410 | /* from 'router.conf' to the 'sdla_setup()' function via the 'port' */ | ||
| 411 | /* parameter */ | ||
| 412 | if (conf->S514_CPU_no[0]){ | ||
| 413 | |||
| 414 | card->hw.S514_cpu_no[0] = conf->S514_CPU_no[0]; | ||
| 415 | card->hw.S514_slot_no = conf->PCI_slot_no; | ||
| 416 | card->hw.auto_pci_cfg = conf->auto_pci_cfg; | ||
| 417 | |||
| 418 | if (card->hw.auto_pci_cfg == WANOPT_YES){ | ||
| 419 | printk(KERN_INFO "%s: Setting CPU to %c and Slot to Auto\n", | ||
| 420 | card->devname, card->hw.S514_cpu_no[0]); | ||
| 421 | }else{ | ||
| 422 | printk(KERN_INFO "%s: Setting CPU to %c and Slot to %i\n", | ||
| 423 | card->devname, card->hw.S514_cpu_no[0], card->hw.S514_slot_no); | ||
| 424 | } | ||
| 425 | |||
| 426 | }else{ | ||
| 427 | /* 508 Card io port and irq initialization */ | ||
| 428 | card->hw.port = conf->ioport; | ||
| 429 | card->hw.irq = (conf->irq == 9) ? 2 : conf->irq; | ||
| 430 | } | ||
| 431 | |||
| 432 | |||
| 433 | /* Compute the virtual address of the card in kernel space */ | ||
| 434 | if(conf->maddr){ | ||
| 435 | card->hw.dpmbase = phys_to_virt(conf->maddr); | ||
| 436 | }else{ | ||
| 437 | card->hw.dpmbase = (void *)conf->maddr; | ||
| 438 | } | ||
| 439 | |||
| 440 | card->hw.dpmsize = SDLA_WINDOWSIZE; | ||
| 441 | |||
| 442 | /* set the adapter type if using an S514 adapter */ | ||
| 443 | card->hw.type = (conf->S514_CPU_no[0]) ? SDLA_S514 : conf->hw_opt[0]; | ||
| 444 | card->hw.pclk = conf->hw_opt[1]; | ||
| 445 | |||
| 446 | err = sdla_setup(&card->hw, conf->data, conf->data_size); | ||
| 447 | if (err){ | ||
| 448 | printk(KERN_INFO "%s: Hardware setup Failed %i\n", | ||
| 449 | card->devname,err); | ||
| 450 | return err; | ||
| 451 | } | ||
| 452 | |||
| 453 | if(card->hw.type != SDLA_S514) | ||
| 454 | irq = (conf->irq == 2) ? 9 : conf->irq; /* IRQ2 -> IRQ9 */ | ||
| 455 | else | ||
| 456 | irq = card->hw.irq; | ||
| 457 | |||
| 458 | /* request an interrupt vector - note that interrupts may be shared */ | ||
| 459 | /* when using the S514 PCI adapter */ | ||
| 460 | |||
| 461 | if(request_irq(irq, sdla_isr, | ||
| 462 | (card->hw.type == SDLA_S514) ? SA_SHIRQ : 0, | ||
| 463 | wandev->name, card)){ | ||
| 464 | |||
| 465 | printk(KERN_INFO "%s: Can't reserve IRQ %d!\n", wandev->name, irq); | ||
| 466 | return -EINVAL; | ||
| 467 | } | ||
| 468 | |||
| 469 | }else{ | ||
| 470 | printk(KERN_INFO "%s: Card Configured %lu or Piggybacking %i!\n", | ||
| 471 | wandev->name,card->configured,card->wandev.piggyback); | ||
| 472 | } | ||
| 473 | |||
| 474 | |||
| 475 | if (!card->configured){ | ||
| 476 | |||
| 477 | /* Initialize the Spin lock */ | ||
| 478 | printk(KERN_INFO "%s: Initializing for SMP\n",wandev->name); | ||
| 479 | |||
| 480 | /* Piggyback spin lock has already been initialized, | ||
| 481 | * in check_s514/s508_conflicts() */ | ||
| 482 | if (!card->wandev.piggyback){ | ||
| 483 | spin_lock_init(&card->wandev.lock); | ||
| 484 | } | ||
| 485 | |||
| 486 | /* Intialize WAN device data space */ | ||
| 487 | wandev->irq = irq; | ||
| 488 | wandev->dma = 0; | ||
| 489 | if(card->hw.type != SDLA_S514){ | ||
| 490 | wandev->ioport = card->hw.port; | ||
| 491 | }else{ | ||
| 492 | wandev->S514_cpu_no[0] = card->hw.S514_cpu_no[0]; | ||
| 493 | wandev->S514_slot_no = card->hw.S514_slot_no; | ||
| 494 | } | ||
| 495 | wandev->maddr = (unsigned long)card->hw.dpmbase; | ||
| 496 | wandev->msize = card->hw.dpmsize; | ||
| 497 | wandev->hw_opt[0] = card->hw.type; | ||
| 498 | wandev->hw_opt[1] = card->hw.pclk; | ||
| 499 | wandev->hw_opt[2] = card->hw.memory; | ||
| 500 | wandev->hw_opt[3] = card->hw.fwid; | ||
| 501 | } | ||
| 502 | |||
| 503 | /* Protocol-specific initialization */ | ||
| 504 | switch (card->hw.fwid) { | ||
| 505 | |||
| 506 | case SFID_X25_502: | ||
| 507 | case SFID_X25_508: | ||
| 508 | printk(KERN_INFO "%s: Starting X.25 Protocol Init.\n", | ||
| 509 | card->devname); | ||
| 510 | err = wpx_init(card, conf); | ||
| 511 | break; | ||
| 512 | case SFID_FR502: | ||
| 513 | case SFID_FR508: | ||
| 514 | printk(KERN_INFO "%s: Starting Frame Relay Protocol Init.\n", | ||
| 515 | card->devname); | ||
| 516 | err = wpf_init(card, conf); | ||
| 517 | break; | ||
| 518 | case SFID_PPP502: | ||
| 519 | case SFID_PPP508: | ||
| 520 | printk(KERN_INFO "%s: Starting PPP Protocol Init.\n", | ||
| 521 | card->devname); | ||
| 522 | err = wpp_init(card, conf); | ||
| 523 | break; | ||
| 524 | |||
| 525 | case SFID_CHDLC508: | ||
| 526 | case SFID_CHDLC514: | ||
| 527 | if (conf->ft1){ | ||
| 528 | printk(KERN_INFO "%s: Starting FT1 CSU/DSU Config Driver.\n", | ||
| 529 | card->devname); | ||
| 530 | err = wpft1_init(card, conf); | ||
| 531 | break; | ||
| 532 | |||
| 533 | }else if (conf->config_id == WANCONFIG_MPPP){ | ||
| 534 | printk(KERN_INFO "%s: Starting Multi-Port PPP Protocol Init.\n", | ||
| 535 | card->devname); | ||
| 536 | err = wsppp_init(card,conf); | ||
| 537 | break; | ||
| 538 | |||
| 539 | }else{ | ||
| 540 | printk(KERN_INFO "%s: Starting CHDLC Protocol Init.\n", | ||
| 541 | card->devname); | ||
| 542 | err = wpc_init(card, conf); | ||
| 543 | break; | ||
| 544 | } | ||
| 545 | default: | ||
| 546 | printk(KERN_INFO "%s: Error, Firmware is not supported %X %X!\n", | ||
| 547 | wandev->name,card->hw.fwid,SFID_CHDLC508); | ||
| 548 | err = -EPROTONOSUPPORT; | ||
| 549 | } | ||
| 550 | |||
| 551 | if (err != 0){ | ||
| 552 | if (err == -EPROTONOSUPPORT){ | ||
| 553 | printk(KERN_INFO | ||
| 554 | "%s: Error, Protocol selected has not been compiled!\n", | ||
| 555 | card->devname); | ||
| 556 | printk(KERN_INFO | ||
| 557 | "%s: Re-configure the kernel and re-build the modules!\n", | ||
| 558 | card->devname); | ||
| 559 | } | ||
| 560 | |||
| 561 | release_hw(card); | ||
| 562 | wandev->state = WAN_UNCONFIGURED; | ||
| 563 | return err; | ||
| 564 | } | ||
| 565 | |||
| 566 | |||
| 567 | /* Reserve I/O region and schedule background task */ | ||
| 568 | if(card->hw.type != SDLA_S514 && !card->wandev.piggyback) | ||
| 569 | if (!request_region(card->hw.port, card->hw.io_range, | ||
| 570 | wandev->name)) { | ||
| 571 | printk(KERN_WARNING "port 0x%04x busy\n", card->hw.port); | ||
| 572 | release_hw(card); | ||
| 573 | wandev->state = WAN_UNCONFIGURED; | ||
| 574 | return -EBUSY; | ||
| 575 | } | ||
| 576 | |||
| 577 | /* Only use the polling routine for the X25 protocol */ | ||
| 578 | |||
| 579 | card->wandev.critical=0; | ||
| 580 | return 0; | ||
| 581 | } | ||
| 582 | |||
| 583 | /*================================================================== | ||
| 584 | * configure_s508_card | ||
| 585 | * | ||
| 586 | * For a S508 adapter, check for a possible configuration error in that | ||
| 587 | * we are loading an adapter in the same IO port as a previously loaded S508 | ||
| 588 | * card. | ||
| 589 | */ | ||
| 590 | |||
| 591 | static int check_s508_conflicts (sdla_t* card,wandev_conf_t* conf, int *irq) | ||
| 592 | { | ||
| 593 | unsigned long smp_flags; | ||
| 594 | int i; | ||
| 595 | |||
| 596 | if (conf->ioport <= 0) { | ||
| 597 | printk(KERN_INFO | ||
| 598 | "%s: can't configure without I/O port address!\n", | ||
| 599 | card->wandev.name); | ||
| 600 | return -EINVAL; | ||
| 601 | } | ||
| 602 | |||
| 603 | if (conf->irq <= 0) { | ||
| 604 | printk(KERN_INFO "%s: can't configure without IRQ!\n", | ||
| 605 | card->wandev.name); | ||
| 606 | return -EINVAL; | ||
| 607 | } | ||
| 608 | |||
| 609 | if (test_bit(0,&card->configured)) | ||
| 610 | return 0; | ||
| 611 | |||
| 612 | |||
| 613 | /* Check for already loaded card with the same IO port and IRQ | ||
| 614 | * If found, copy its hardware configuration and use its | ||
| 615 | * resources (i.e. piggybacking) | ||
| 616 | */ | ||
| 617 | |||
| 618 | for (i = 0; i < ncards; i++) { | ||
| 619 | sdla_t *nxt_card = &card_array[i]; | ||
| 620 | |||
| 621 | /* Skip the current card ptr */ | ||
| 622 | if (nxt_card == card) | ||
| 623 | continue; | ||
| 624 | |||
| 625 | |||
| 626 | /* Find a card that is already configured with the | ||
| 627 | * same IO Port */ | ||
| 628 | if ((nxt_card->hw.type == SDLA_S508) && | ||
| 629 | (nxt_card->hw.port == conf->ioport) && | ||
| 630 | (nxt_card->next == NULL)){ | ||
| 631 | |||
| 632 | /* We found a card the card that has same configuration | ||
| 633 | * as us. This means, that we must setup this card in | ||
| 634 | * piggibacking mode. However, only CHDLC and MPPP protocol | ||
| 635 | * support this setup */ | ||
| 636 | |||
| 637 | if ((conf->config_id == WANCONFIG_CHDLC || | ||
| 638 | conf->config_id == WANCONFIG_MPPP) && | ||
| 639 | (nxt_card->wandev.config_id == WANCONFIG_CHDLC || | ||
| 640 | nxt_card->wandev.config_id == WANCONFIG_MPPP)){ | ||
| 641 | |||
| 642 | *irq = nxt_card->hw.irq; | ||
| 643 | memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t)); | ||
| 644 | |||
| 645 | /* The master could already be running, we must | ||
| 646 | * set this as a critical area */ | ||
| 647 | lock_adapter_irq(&nxt_card->wandev.lock, &smp_flags); | ||
| 648 | |||
| 649 | nxt_card->next = card; | ||
| 650 | card->next = nxt_card; | ||
| 651 | |||
| 652 | card->wandev.piggyback = WANOPT_YES; | ||
| 653 | |||
| 654 | /* We must initialise the piggiback spin lock here | ||
| 655 | * since isr will try to lock card->next if it | ||
| 656 | * exists */ | ||
| 657 | spin_lock_init(&card->wandev.lock); | ||
| 658 | |||
| 659 | unlock_adapter_irq(&nxt_card->wandev.lock, &smp_flags); | ||
| 660 | break; | ||
| 661 | }else{ | ||
| 662 | /* Trying to run piggibacking with a wrong protocol */ | ||
| 663 | printk(KERN_INFO "%s: ERROR: Resource busy, ioport: 0x%x\n" | ||
| 664 | "%s: This protocol doesn't support\n" | ||
| 665 | "%s: multi-port operation!\n", | ||
| 666 | card->devname,nxt_card->hw.port, | ||
| 667 | card->devname,card->devname); | ||
| 668 | return -EEXIST; | ||
| 669 | } | ||
| 670 | } | ||
| 671 | } | ||
| 672 | |||
| 673 | |||
| 674 | /* Make sure I/O port region is available only if we are the | ||
| 675 | * master device. If we are running in piggybacking mode, | ||
| 676 | * we will use the resources of the master card. */ | ||
| 677 | if (!card->wandev.piggyback) { | ||
| 678 | struct resource *rr = | ||
| 679 | request_region(conf->ioport, SDLA_MAXIORANGE, "sdlamain"); | ||
| 680 | release_region(conf->ioport, SDLA_MAXIORANGE); | ||
| 681 | |||
| 682 | if (!rr) { | ||
| 683 | printk(KERN_INFO | ||
| 684 | "%s: I/O region 0x%X - 0x%X is in use!\n", | ||
| 685 | card->wandev.name, conf->ioport, | ||
| 686 | conf->ioport + SDLA_MAXIORANGE - 1); | ||
| 687 | return -EINVAL; | ||
| 688 | } | ||
| 689 | } | ||
| 690 | |||
| 691 | return 0; | ||
| 692 | } | ||
| 693 | |||
| 694 | /*================================================================== | ||
| 695 | * configure_s514_card | ||
| 696 | * | ||
| 697 | * For a S514 adapter, check for a possible configuration error in that | ||
| 698 | * we are loading an adapter in the same slot as a previously loaded S514 | ||
| 699 | * card. | ||
| 700 | */ | ||
| 701 | |||
| 702 | |||
| 703 | static int check_s514_conflicts(sdla_t* card,wandev_conf_t* conf, int *irq) | ||
| 704 | { | ||
| 705 | unsigned long smp_flags; | ||
| 706 | int i; | ||
| 707 | |||
| 708 | if (test_bit(0,&card->configured)) | ||
| 709 | return 0; | ||
| 710 | |||
| 711 | |||
| 712 | /* Check for already loaded card with the same IO port and IRQ | ||
| 713 | * If found, copy its hardware configuration and use its | ||
| 714 | * resources (i.e. piggybacking) | ||
| 715 | */ | ||
| 716 | |||
| 717 | for (i = 0; i < ncards; i ++) { | ||
| 718 | |||
| 719 | sdla_t* nxt_card = &card_array[i]; | ||
| 720 | if(nxt_card == card) | ||
| 721 | continue; | ||
| 722 | |||
| 723 | if((nxt_card->hw.type == SDLA_S514) && | ||
| 724 | (nxt_card->hw.S514_slot_no == conf->PCI_slot_no) && | ||
| 725 | (nxt_card->hw.S514_cpu_no[0] == conf->S514_CPU_no[0])&& | ||
| 726 | (nxt_card->next == NULL)){ | ||
| 727 | |||
| 728 | |||
| 729 | if ((conf->config_id == WANCONFIG_CHDLC || | ||
| 730 | conf->config_id == WANCONFIG_MPPP) && | ||
| 731 | (nxt_card->wandev.config_id == WANCONFIG_CHDLC || | ||
| 732 | nxt_card->wandev.config_id == WANCONFIG_MPPP)){ | ||
| 733 | |||
| 734 | *irq = nxt_card->hw.irq; | ||
| 735 | memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t)); | ||
| 736 | |||
| 737 | /* The master could already be running, we must | ||
| 738 | * set this as a critical area */ | ||
| 739 | lock_adapter_irq(&nxt_card->wandev.lock,&smp_flags); | ||
| 740 | nxt_card->next = card; | ||
| 741 | card->next = nxt_card; | ||
| 742 | |||
| 743 | card->wandev.piggyback = WANOPT_YES; | ||
| 744 | |||
| 745 | /* We must initialise the piggiback spin lock here | ||
| 746 | * since isr will try to lock card->next if it | ||
| 747 | * exists */ | ||
| 748 | spin_lock_init(&card->wandev.lock); | ||
| 749 | |||
| 750 | unlock_adapter_irq(&nxt_card->wandev.lock,&smp_flags); | ||
| 751 | |||
| 752 | }else{ | ||
| 753 | /* Trying to run piggibacking with a wrong protocol */ | ||
| 754 | printk(KERN_INFO "%s: ERROR: Resource busy: CPU %c PCISLOT %i\n" | ||
| 755 | "%s: This protocol doesn't support\n" | ||
| 756 | "%s: multi-port operation!\n", | ||
| 757 | card->devname, | ||
| 758 | conf->S514_CPU_no[0],conf->PCI_slot_no, | ||
| 759 | card->devname,card->devname); | ||
| 760 | return -EEXIST; | ||
| 761 | } | ||
| 762 | } | ||
| 763 | } | ||
| 764 | |||
| 765 | return 0; | ||
| 766 | } | ||
| 767 | |||
| 768 | |||
| 769 | |||
| 770 | /*============================================================================ | ||
| 771 | * Shut down WAN link driver. | ||
| 772 | * o shut down adapter hardware | ||
| 773 | * o release system resources. | ||
| 774 | * | ||
| 775 | * This function is called by the router when device is being unregistered or | ||
| 776 | * when it handles ROUTER_DOWN IOCTL. | ||
| 777 | */ | ||
| 778 | static int shutdown(struct wan_device* wandev) | ||
| 779 | { | ||
| 780 | sdla_t *card; | ||
| 781 | int err=0; | ||
| 782 | |||
| 783 | /* sanity checks */ | ||
| 784 | if ((wandev == NULL) || (wandev->private == NULL)){ | ||
| 785 | return -EFAULT; | ||
| 786 | } | ||
| 787 | |||
| 788 | if (wandev->state == WAN_UNCONFIGURED){ | ||
| 789 | return 0; | ||
| 790 | } | ||
| 791 | |||
| 792 | card = wandev->private; | ||
| 793 | |||
| 794 | if (card->tty_opt){ | ||
| 795 | if (card->tty_open){ | ||
| 796 | printk(KERN_INFO | ||
| 797 | "%s: Shutdown Failed: TTY is still open\n", | ||
| 798 | card->devname); | ||
| 799 | return -EBUSY; | ||
| 800 | } | ||
| 801 | } | ||
| 802 | |||
| 803 | wandev->state = WAN_UNCONFIGURED; | ||
| 804 | |||
| 805 | set_bit(PERI_CRIT,(void*)&wandev->critical); | ||
| 806 | |||
| 807 | /* In case of piggibacking, make sure that | ||
| 808 | * we never try to shutdown both devices at the same | ||
| 809 | * time, because they depend on one another */ | ||
| 810 | |||
| 811 | if (card->disable_comm){ | ||
| 812 | card->disable_comm(card); | ||
| 813 | } | ||
| 814 | |||
| 815 | /* Release Resources */ | ||
| 816 | release_hw(card); | ||
| 817 | |||
| 818 | /* only free the allocated I/O range if not an S514 adapter */ | ||
| 819 | if (wandev->hw_opt[0] != SDLA_S514 && !card->configured){ | ||
| 820 | release_region(card->hw.port, card->hw.io_range); | ||
| 821 | } | ||
| 822 | |||
| 823 | if (!card->configured){ | ||
| 824 | memset(&card->hw, 0, sizeof(sdlahw_t)); | ||
| 825 | if (card->next){ | ||
| 826 | memset(&card->next->hw, 0, sizeof(sdlahw_t)); | ||
| 827 | } | ||
| 828 | } | ||
| 829 | |||
| 830 | |||
| 831 | clear_bit(PERI_CRIT,(void*)&wandev->critical); | ||
| 832 | return err; | ||
| 833 | } | ||
| 834 | |||
| 835 | static void release_hw (sdla_t *card) | ||
| 836 | { | ||
| 837 | sdla_t *nxt_card; | ||
| 838 | |||
| 839 | |||
| 840 | /* Check if next device exists */ | ||
| 841 | if (card->next){ | ||
| 842 | nxt_card = card->next; | ||
| 843 | /* If next device is down then release resources */ | ||
| 844 | if (nxt_card->wandev.state == WAN_UNCONFIGURED){ | ||
| 845 | if (card->wandev.piggyback){ | ||
| 846 | /* If this device is piggyback then use | ||
| 847 | * information of the master device | ||
| 848 | */ | ||
| 849 | printk(KERN_INFO "%s: Piggyback shutting down\n",card->devname); | ||
| 850 | sdla_down(&card->next->hw); | ||
| 851 | free_irq(card->wandev.irq, card->next); | ||
| 852 | card->configured = 0; | ||
| 853 | card->next->configured = 0; | ||
| 854 | card->wandev.piggyback = 0; | ||
| 855 | }else{ | ||
| 856 | /* Master device shutting down */ | ||
| 857 | printk(KERN_INFO "%s: Master shutting down\n",card->devname); | ||
| 858 | sdla_down(&card->hw); | ||
| 859 | free_irq(card->wandev.irq, card); | ||
| 860 | card->configured = 0; | ||
| 861 | card->next->configured = 0; | ||
| 862 | } | ||
| 863 | }else{ | ||
| 864 | printk(KERN_INFO "%s: Device still running %i\n", | ||
| 865 | nxt_card->devname,nxt_card->wandev.state); | ||
| 866 | |||
| 867 | card->configured = 1; | ||
| 868 | } | ||
| 869 | }else{ | ||
| 870 | printk(KERN_INFO "%s: Master shutting down\n",card->devname); | ||
| 871 | sdla_down(&card->hw); | ||
| 872 | free_irq(card->wandev.irq, card); | ||
| 873 | card->configured = 0; | ||
| 874 | } | ||
| 875 | return; | ||
| 876 | } | ||
| 877 | |||
| 878 | |||
| 879 | /*============================================================================ | ||
| 880 | * Driver I/O control. | ||
| 881 | * o verify arguments | ||
| 882 | * o perform requested action | ||
| 883 | * | ||
| 884 | * This function is called when router handles one of the reserved user | ||
| 885 | * IOCTLs. Note that 'arg' stil points to user address space. | ||
| 886 | */ | ||
| 887 | static int ioctl(struct wan_device* wandev, unsigned cmd, unsigned long arg) | ||
| 888 | { | ||
| 889 | sdla_t* card; | ||
| 890 | int err; | ||
| 891 | |||
| 892 | /* sanity checks */ | ||
| 893 | if ((wandev == NULL) || (wandev->private == NULL)) | ||
| 894 | return -EFAULT; | ||
| 895 | if (wandev->state == WAN_UNCONFIGURED) | ||
| 896 | return -ENODEV; | ||
| 897 | |||
| 898 | card = wandev->private; | ||
| 899 | |||
| 900 | if(card->hw.type != SDLA_S514){ | ||
| 901 | disable_irq(card->hw.irq); | ||
| 902 | } | ||
| 903 | |||
| 904 | if (test_bit(SEND_CRIT, (void*)&wandev->critical)) { | ||
| 905 | return -EAGAIN; | ||
| 906 | } | ||
| 907 | |||
| 908 | switch (cmd) { | ||
| 909 | case WANPIPE_DUMP: | ||
| 910 | err = ioctl_dump(wandev->private, (void*)arg); | ||
| 911 | break; | ||
| 912 | |||
| 913 | case WANPIPE_EXEC: | ||
| 914 | err = ioctl_exec(wandev->private, (void*)arg, cmd); | ||
| 915 | break; | ||
| 916 | default: | ||
| 917 | err = -EINVAL; | ||
| 918 | } | ||
| 919 | |||
| 920 | return err; | ||
| 921 | } | ||
| 922 | |||
| 923 | /****** Driver IOCTL Handlers ***********************************************/ | ||
| 924 | |||
| 925 | /*============================================================================ | ||
| 926 | * Dump adapter memory to user buffer. | ||
| 927 | * o verify request structure | ||
| 928 | * o copy request structure to kernel data space | ||
| 929 | * o verify length/offset | ||
| 930 | * o verify user buffer | ||
| 931 | * o copy adapter memory image to user buffer | ||
| 932 | * | ||
| 933 | * Note: when dumping memory, this routine switches curent dual-port memory | ||
| 934 | * vector, so care must be taken to avoid racing conditions. | ||
| 935 | */ | ||
| 936 | static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump) | ||
| 937 | { | ||
| 938 | sdla_dump_t dump; | ||
| 939 | unsigned winsize; | ||
| 940 | unsigned long oldvec; /* DPM window vector */ | ||
| 941 | unsigned long smp_flags; | ||
| 942 | int err = 0; | ||
| 943 | |||
| 944 | if(copy_from_user((void*)&dump, (void*)u_dump, sizeof(sdla_dump_t))) | ||
| 945 | return -EFAULT; | ||
| 946 | |||
| 947 | if ((dump.magic != WANPIPE_MAGIC) || | ||
| 948 | (dump.offset + dump.length > card->hw.memory)) | ||
| 949 | return -EINVAL; | ||
| 950 | |||
| 951 | winsize = card->hw.dpmsize; | ||
| 952 | |||
| 953 | if(card->hw.type != SDLA_S514) { | ||
| 954 | |||
| 955 | lock_adapter_irq(&card->wandev.lock, &smp_flags); | ||
| 956 | |||
| 957 | oldvec = card->hw.vector; | ||
| 958 | while (dump.length) { | ||
| 959 | /* current offset */ | ||
| 960 | unsigned pos = dump.offset % winsize; | ||
| 961 | /* current vector */ | ||
| 962 | unsigned long vec = dump.offset - pos; | ||
| 963 | unsigned len = (dump.length > (winsize - pos)) ? | ||
| 964 | (winsize - pos) : dump.length; | ||
| 965 | /* relocate window */ | ||
| 966 | if (sdla_mapmem(&card->hw, vec) != 0) { | ||
| 967 | err = -EIO; | ||
| 968 | break; | ||
| 969 | } | ||
| 970 | |||
| 971 | if(copy_to_user((void *)dump.ptr, | ||
| 972 | (u8 *)card->hw.dpmbase + pos, len)){ | ||
| 973 | |||
| 974 | unlock_adapter_irq(&card->wandev.lock, &smp_flags); | ||
| 975 | return -EFAULT; | ||
| 976 | } | ||
| 977 | |||
| 978 | dump.length -= len; | ||
| 979 | dump.offset += len; | ||
| 980 | dump.ptr = (char*)dump.ptr + len; | ||
| 981 | } | ||
| 982 | |||
| 983 | sdla_mapmem(&card->hw, oldvec);/* restore DPM window position */ | ||
| 984 | unlock_adapter_irq(&card->wandev.lock, &smp_flags); | ||
| 985 | |||
| 986 | }else { | ||
| 987 | |||
| 988 | if(copy_to_user((void *)dump.ptr, | ||
| 989 | (u8 *)card->hw.dpmbase + dump.offset, dump.length)){ | ||
| 990 | return -EFAULT; | ||
| 991 | } | ||
| 992 | } | ||
| 993 | |||
| 994 | return err; | ||
| 995 | } | ||
| 996 | |||
| 997 | /*============================================================================ | ||
| 998 | * Execute adapter firmware command. | ||
| 999 | * o verify request structure | ||
| 1000 | * o copy request structure to kernel data space | ||
| 1001 | * o call protocol-specific 'exec' function | ||
| 1002 | */ | ||
| 1003 | static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec, int cmd) | ||
| 1004 | { | ||
| 1005 | sdla_exec_t exec; | ||
| 1006 | int err=0; | ||
| 1007 | |||
| 1008 | if (card->exec == NULL && cmd == WANPIPE_EXEC){ | ||
| 1009 | return -ENODEV; | ||
| 1010 | } | ||
| 1011 | |||
| 1012 | if(copy_from_user((void*)&exec, (void*)u_exec, sizeof(sdla_exec_t))) | ||
| 1013 | return -EFAULT; | ||
| 1014 | |||
| 1015 | if ((exec.magic != WANPIPE_MAGIC) || (exec.cmd == NULL)) | ||
| 1016 | return -EINVAL; | ||
| 1017 | |||
| 1018 | switch (cmd) { | ||
| 1019 | case WANPIPE_EXEC: | ||
| 1020 | err = card->exec(card, exec.cmd, exec.data); | ||
| 1021 | break; | ||
| 1022 | } | ||
| 1023 | return err; | ||
| 1024 | } | ||
| 1025 | |||
| 1026 | /******* Miscellaneous ******************************************************/ | ||
| 1027 | |||
| 1028 | /*============================================================================ | ||
| 1029 | * SDLA Interrupt Service Routine. | ||
| 1030 | * o acknowledge SDLA hardware interrupt. | ||
| 1031 | * o call protocol-specific interrupt service routine, if any. | ||
| 1032 | */ | ||
| 1033 | STATIC irqreturn_t sdla_isr (int irq, void* dev_id, struct pt_regs *regs) | ||
| 1034 | { | ||
| 1035 | #define card ((sdla_t*)dev_id) | ||
| 1036 | |||
| 1037 | if(card->hw.type == SDLA_S514) { /* handle interrrupt on S514 */ | ||
| 1038 | u32 int_status; | ||
| 1039 | unsigned char CPU_no = card->hw.S514_cpu_no[0]; | ||
| 1040 | unsigned char card_found_for_IRQ; | ||
| 1041 | u8 IRQ_count = 0; | ||
| 1042 | |||
| 1043 | for(;;) { | ||
| 1044 | |||
| 1045 | read_S514_int_stat(&card->hw, &int_status); | ||
| 1046 | |||
| 1047 | /* check if the interrupt is for this device */ | ||
| 1048 | if(!((unsigned char)int_status & | ||
| 1049 | (IRQ_CPU_A | IRQ_CPU_B))) | ||
| 1050 | return IRQ_HANDLED; | ||
| 1051 | |||
| 1052 | /* if the IRQ is for both CPUs on the same adapter, */ | ||
| 1053 | /* then alter the interrupt status so as to handle */ | ||
| 1054 | /* one CPU at a time */ | ||
| 1055 | if(((unsigned char)int_status & (IRQ_CPU_A | IRQ_CPU_B)) | ||
| 1056 | == (IRQ_CPU_A | IRQ_CPU_B)) { | ||
| 1057 | int_status &= (CPU_no == S514_CPU_A) ? | ||
| 1058 | ~IRQ_CPU_B : ~IRQ_CPU_A; | ||
| 1059 | } | ||
| 1060 | |||
| 1061 | card_found_for_IRQ = 0; | ||
| 1062 | |||
| 1063 | /* check to see that the CPU number for this device */ | ||
| 1064 | /* corresponds to the interrupt status read */ | ||
| 1065 | switch (CPU_no) { | ||
| 1066 | case S514_CPU_A: | ||
| 1067 | if((unsigned char)int_status & | ||
| 1068 | IRQ_CPU_A) | ||
| 1069 | card_found_for_IRQ = 1; | ||
| 1070 | break; | ||
| 1071 | |||
| 1072 | case S514_CPU_B: | ||
| 1073 | if((unsigned char)int_status & | ||
| 1074 | IRQ_CPU_B) | ||
| 1075 | card_found_for_IRQ = 1; | ||
| 1076 | break; | ||
| 1077 | } | ||
| 1078 | |||
| 1079 | /* exit if the interrupt is for another CPU on the */ | ||
| 1080 | /* same IRQ */ | ||
| 1081 | if(!card_found_for_IRQ) | ||
| 1082 | return IRQ_HANDLED; | ||
| 1083 | |||
| 1084 | if (!card || | ||
| 1085 | (card->wandev.state == WAN_UNCONFIGURED && !card->configured)){ | ||
| 1086 | printk(KERN_INFO | ||
| 1087 | "Received IRQ %d for CPU #%c\n", | ||
| 1088 | irq, CPU_no); | ||
| 1089 | printk(KERN_INFO | ||
| 1090 | "IRQ for unconfigured adapter\n"); | ||
| 1091 | S514_intack(&card->hw, int_status); | ||
| 1092 | return IRQ_HANDLED; | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | if (card->in_isr) { | ||
| 1096 | printk(KERN_INFO | ||
| 1097 | "%s: interrupt re-entrancy on IRQ %d\n", | ||
| 1098 | card->devname, card->wandev.irq); | ||
| 1099 | S514_intack(&card->hw, int_status); | ||
| 1100 | return IRQ_HANDLED; | ||
| 1101 | } | ||
| 1102 | |||
| 1103 | spin_lock(&card->wandev.lock); | ||
| 1104 | if (card->next){ | ||
| 1105 | spin_lock(&card->next->wandev.lock); | ||
| 1106 | } | ||
| 1107 | |||
| 1108 | S514_intack(&card->hw, int_status); | ||
| 1109 | if (card->isr) | ||
| 1110 | card->isr(card); | ||
| 1111 | |||
| 1112 | if (card->next){ | ||
| 1113 | spin_unlock(&card->next->wandev.lock); | ||
| 1114 | } | ||
| 1115 | spin_unlock(&card->wandev.lock); | ||
| 1116 | |||
| 1117 | /* handle a maximum of two interrupts (one for each */ | ||
| 1118 | /* CPU on the adapter) before returning */ | ||
| 1119 | if((++ IRQ_count) == 2) | ||
| 1120 | return IRQ_HANDLED; | ||
| 1121 | } | ||
| 1122 | } | ||
| 1123 | |||
| 1124 | else { /* handle interrupt on S508 adapter */ | ||
| 1125 | |||
| 1126 | if (!card || ((card->wandev.state == WAN_UNCONFIGURED) && !card->configured)) | ||
| 1127 | return IRQ_HANDLED; | ||
| 1128 | |||
| 1129 | if (card->in_isr) { | ||
| 1130 | printk(KERN_INFO | ||
| 1131 | "%s: interrupt re-entrancy on IRQ %d!\n", | ||
| 1132 | card->devname, card->wandev.irq); | ||
| 1133 | return IRQ_HANDLED; | ||
| 1134 | } | ||
| 1135 | |||
| 1136 | spin_lock(&card->wandev.lock); | ||
| 1137 | if (card->next){ | ||
| 1138 | spin_lock(&card->next->wandev.lock); | ||
| 1139 | } | ||
| 1140 | |||
| 1141 | sdla_intack(&card->hw); | ||
| 1142 | if (card->isr) | ||
| 1143 | card->isr(card); | ||
| 1144 | |||
| 1145 | if (card->next){ | ||
| 1146 | spin_unlock(&card->next->wandev.lock); | ||
| 1147 | } | ||
| 1148 | spin_unlock(&card->wandev.lock); | ||
| 1149 | |||
| 1150 | } | ||
| 1151 | return IRQ_HANDLED; | ||
| 1152 | #undef card | ||
| 1153 | } | ||
| 1154 | |||
| 1155 | /*============================================================================ | ||
| 1156 | * This routine is called by the protocol-specific modules when network | ||
| 1157 | * interface is being open. The only reason we need this, is because we | ||
| 1158 | * have to call MOD_INC_USE_COUNT, but cannot include 'module.h' where it's | ||
| 1159 | * defined more than once into the same kernel module. | ||
| 1160 | */ | ||
| 1161 | void wanpipe_open (sdla_t* card) | ||
| 1162 | { | ||
| 1163 | ++card->open_cnt; | ||
| 1164 | } | ||
| 1165 | |||
| 1166 | /*============================================================================ | ||
| 1167 | * This routine is called by the protocol-specific modules when network | ||
| 1168 | * interface is being closed. The only reason we need this, is because we | ||
| 1169 | * have to call MOD_DEC_USE_COUNT, but cannot include 'module.h' where it's | ||
| 1170 | * defined more than once into the same kernel module. | ||
| 1171 | */ | ||
| 1172 | void wanpipe_close (sdla_t* card) | ||
| 1173 | { | ||
| 1174 | --card->open_cnt; | ||
| 1175 | } | ||
| 1176 | |||
| 1177 | /*============================================================================ | ||
| 1178 | * Set WAN device state. | ||
| 1179 | */ | ||
| 1180 | void wanpipe_set_state (sdla_t* card, int state) | ||
| 1181 | { | ||
| 1182 | if (card->wandev.state != state) { | ||
| 1183 | switch (state) { | ||
| 1184 | case WAN_CONNECTED: | ||
| 1185 | printk (KERN_INFO "%s: link connected!\n", | ||
| 1186 | card->devname); | ||
| 1187 | break; | ||
| 1188 | |||
| 1189 | case WAN_CONNECTING: | ||
| 1190 | printk (KERN_INFO "%s: link connecting...\n", | ||
| 1191 | card->devname); | ||
| 1192 | break; | ||
| 1193 | |||
| 1194 | case WAN_DISCONNECTED: | ||
| 1195 | printk (KERN_INFO "%s: link disconnected!\n", | ||
| 1196 | card->devname); | ||
| 1197 | break; | ||
| 1198 | } | ||
| 1199 | card->wandev.state = state; | ||
| 1200 | } | ||
| 1201 | card->state_tick = jiffies; | ||
| 1202 | } | ||
| 1203 | |||
| 1204 | sdla_t * wanpipe_find_card (char *name) | ||
| 1205 | { | ||
| 1206 | int cnt; | ||
| 1207 | for (cnt = 0; cnt < ncards; ++ cnt) { | ||
| 1208 | sdla_t* card = &card_array[cnt]; | ||
| 1209 | if (!strcmp(card->devname,name)) | ||
| 1210 | return card; | ||
| 1211 | } | ||
| 1212 | return NULL; | ||
| 1213 | } | ||
| 1214 | |||
| 1215 | sdla_t * wanpipe_find_card_num (int num) | ||
| 1216 | { | ||
| 1217 | if (num < 1 || num > ncards) | ||
| 1218 | return NULL; | ||
| 1219 | num--; | ||
| 1220 | return &card_array[num]; | ||
| 1221 | } | ||
| 1222 | |||
| 1223 | /* | ||
| 1224 | * @work_pointer: work_struct to be done; | ||
| 1225 | * should already have PREPARE_WORK() or | ||
| 1226 | * INIT_WORK() done on it by caller; | ||
| 1227 | */ | ||
| 1228 | void wanpipe_queue_work (struct work_struct *work_pointer) | ||
| 1229 | { | ||
| 1230 | if (test_and_set_bit(1, (void*)&wanpipe_bh_critical)) | ||
| 1231 | printk(KERN_INFO "CRITICAL IN QUEUING WORK\n"); | ||
| 1232 | |||
| 1233 | queue_work(wanpipe_wq, work_pointer); | ||
| 1234 | clear_bit(1,(void*)&wanpipe_bh_critical); | ||
| 1235 | } | ||
| 1236 | |||
| 1237 | void wakeup_sk_bh(struct net_device *dev) | ||
| 1238 | { | ||
| 1239 | wanpipe_common_t *chan = dev->priv; | ||
| 1240 | |||
| 1241 | if (test_bit(0,&chan->common_critical)) | ||
| 1242 | return; | ||
| 1243 | |||
| 1244 | if (chan->sk && chan->tx_timer){ | ||
| 1245 | chan->tx_timer->expires=jiffies+1; | ||
| 1246 | add_timer(chan->tx_timer); | ||
| 1247 | } | ||
| 1248 | } | ||
| 1249 | |||
| 1250 | int change_dev_flags(struct net_device *dev, unsigned flags) | ||
| 1251 | { | ||
| 1252 | struct ifreq if_info; | ||
| 1253 | mm_segment_t fs = get_fs(); | ||
| 1254 | int err; | ||
| 1255 | |||
| 1256 | memset(&if_info, 0, sizeof(if_info)); | ||
| 1257 | strcpy(if_info.ifr_name, dev->name); | ||
| 1258 | if_info.ifr_flags = flags; | ||
| 1259 | |||
| 1260 | set_fs(get_ds()); /* get user space block */ | ||
| 1261 | err = devinet_ioctl(SIOCSIFFLAGS, &if_info); | ||
| 1262 | set_fs(fs); | ||
| 1263 | |||
| 1264 | return err; | ||
| 1265 | } | ||
| 1266 | |||
| 1267 | unsigned long get_ip_address(struct net_device *dev, int option) | ||
| 1268 | { | ||
| 1269 | |||
| 1270 | struct in_ifaddr *ifaddr; | ||
| 1271 | struct in_device *in_dev; | ||
| 1272 | unsigned long addr = 0; | ||
| 1273 | |||
| 1274 | rcu_read_lock(); | ||
| 1275 | if ((in_dev = __in_dev_get_rcu(dev)) == NULL){ | ||
| 1276 | goto out; | ||
| 1277 | } | ||
| 1278 | |||
| 1279 | if ((ifaddr = in_dev->ifa_list)== NULL ){ | ||
| 1280 | goto out; | ||
| 1281 | } | ||
| 1282 | |||
| 1283 | switch (option){ | ||
| 1284 | |||
| 1285 | case WAN_LOCAL_IP: | ||
| 1286 | addr = ifaddr->ifa_local; | ||
| 1287 | break; | ||
| 1288 | |||
| 1289 | case WAN_POINTOPOINT_IP: | ||
| 1290 | addr = ifaddr->ifa_address; | ||
| 1291 | break; | ||
| 1292 | |||
| 1293 | case WAN_NETMASK_IP: | ||
| 1294 | addr = ifaddr->ifa_mask; | ||
| 1295 | break; | ||
| 1296 | |||
| 1297 | case WAN_BROADCAST_IP: | ||
| 1298 | addr = ifaddr->ifa_broadcast; | ||
| 1299 | break; | ||
| 1300 | default: | ||
| 1301 | break; | ||
| 1302 | } | ||
| 1303 | |||
| 1304 | out: | ||
| 1305 | rcu_read_unlock(); | ||
| 1306 | return addr; | ||
| 1307 | } | ||
| 1308 | |||
| 1309 | void add_gateway(sdla_t *card, struct net_device *dev) | ||
| 1310 | { | ||
| 1311 | mm_segment_t oldfs; | ||
| 1312 | struct rtentry route; | ||
| 1313 | int res; | ||
| 1314 | |||
| 1315 | memset((char*)&route,0,sizeof(struct rtentry)); | ||
| 1316 | |||
| 1317 | ((struct sockaddr_in *) | ||
| 1318 | &(route.rt_dst))->sin_addr.s_addr = 0; | ||
| 1319 | ((struct sockaddr_in *) | ||
| 1320 | &(route.rt_dst))->sin_family = AF_INET; | ||
| 1321 | |||
| 1322 | ((struct sockaddr_in *) | ||
| 1323 | &(route.rt_genmask))->sin_addr.s_addr = 0; | ||
| 1324 | ((struct sockaddr_in *) | ||
| 1325 | &(route.rt_genmask)) ->sin_family = AF_INET; | ||
| 1326 | |||
| 1327 | |||
| 1328 | route.rt_flags = 0; | ||
| 1329 | route.rt_dev = dev->name; | ||
| 1330 | |||
| 1331 | oldfs = get_fs(); | ||
| 1332 | set_fs(get_ds()); | ||
| 1333 | res = ip_rt_ioctl(SIOCADDRT,&route); | ||
| 1334 | set_fs(oldfs); | ||
| 1335 | |||
| 1336 | if (res == 0){ | ||
| 1337 | printk(KERN_INFO "%s: Gateway added for %s\n", | ||
| 1338 | card->devname,dev->name); | ||
| 1339 | } | ||
| 1340 | |||
| 1341 | return; | ||
| 1342 | } | ||
| 1343 | |||
| 1344 | MODULE_LICENSE("GPL"); | ||
| 1345 | |||
| 1346 | /****** End *********************************************************/ | ||
diff --git a/drivers/net/wan/wanpipe_multppp.c b/drivers/net/wan/wanpipe_multppp.c deleted file mode 100644 index 812a1183c502..000000000000 --- a/drivers/net/wan/wanpipe_multppp.c +++ /dev/null | |||
| @@ -1,2358 +0,0 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * wanpipe_multppp.c Multi-Port PPP driver module. | ||
| 3 | * | ||
| 4 | * Authors: Nenad Corbic <ncorbic@sangoma.com> | ||
| 5 | * | ||
| 6 | * Copyright: (c) 1995-2001 Sangoma Technologies Inc. | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or | ||
| 9 | * modify it under the terms of the GNU General Public License | ||
| 10 | * as published by the Free Software Foundation; either version | ||
| 11 | * 2 of the License, or (at your option) any later version. | ||
| 12 | * ============================================================================ | ||
| 13 | * Dec 15 2000 Updated for 2.4.X kernel | ||
| 14 | * Nov 15 2000 Fixed the SyncPPP support for kernels 2.2.16 and higher. | ||
| 15 | * The pppstruct has changed. | ||
| 16 | * Jul 13 2000 Using the kernel Syncppp module on top of RAW Wanpipe CHDLC | ||
| 17 | * module. | ||
| 18 | *****************************************************************************/ | ||
| 19 | |||
| 20 | #include <linux/module.h> | ||
| 21 | #include <linux/kernel.h> /* printk(), and other useful stuff */ | ||
| 22 | #include <linux/stddef.h> /* offsetof(), etc. */ | ||
| 23 | #include <linux/errno.h> /* return codes */ | ||
| 24 | #include <linux/string.h> /* inline memset(), etc. */ | ||
| 25 | #include <linux/slab.h> /* kmalloc(), kfree() */ | ||
| 26 | #include <linux/wanrouter.h> /* WAN router definitions */ | ||
| 27 | #include <linux/wanpipe.h> /* WANPIPE common user API definitions */ | ||
| 28 | #include <linux/if_arp.h> /* ARPHRD_* defines */ | ||
| 29 | #include <linux/jiffies.h> /* time_after() macro */ | ||
| 30 | |||
| 31 | #include <linux/in.h> /* sockaddr_in */ | ||
| 32 | #include <linux/inet.h> | ||
| 33 | #include <linux/if.h> | ||
| 34 | #include <asm/byteorder.h> /* htons(), etc. */ | ||
| 35 | #include <linux/sdlapci.h> | ||
| 36 | #include <asm/io.h> | ||
| 37 | |||
| 38 | #include <linux/sdla_chdlc.h> /* CHDLC firmware API definitions */ | ||
| 39 | #include <linux/sdla_asy.h> /* CHDLC (async) API definitions */ | ||
| 40 | |||
| 41 | #include <linux/if_wanpipe_common.h> /* Socket Driver common area */ | ||
| 42 | #include <linux/if_wanpipe.h> | ||
| 43 | |||
| 44 | |||
| 45 | #include <linux/inetdevice.h> | ||
| 46 | #include <asm/uaccess.h> | ||
| 47 | |||
| 48 | #include <net/syncppp.h> | ||
| 49 | |||
| 50 | |||
| 51 | /****** Defines & Macros ****************************************************/ | ||
| 52 | |||
| 53 | #ifdef _DEBUG_ | ||
| 54 | #define STATIC | ||
| 55 | #else | ||
| 56 | #define STATIC static | ||
| 57 | #endif | ||
| 58 | |||
| 59 | /* reasons for enabling the timer interrupt on the adapter */ | ||
| 60 | #define TMR_INT_ENABLED_UDP 0x01 | ||
| 61 | #define TMR_INT_ENABLED_UPDATE 0x02 | ||
| 62 | #define TMR_INT_ENABLED_CONFIG 0x04 | ||
| 63 | |||
| 64 | #define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ | ||
| 65 | #define CHDLC_HDR_LEN 1 | ||
| 66 | |||
| 67 | #define IFF_POINTTOPOINT 0x10 | ||
| 68 | |||
| 69 | #define CHDLC_API 0x01 | ||
| 70 | |||
| 71 | #define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) | ||
| 72 | #define MAX_BH_BUFF 10 | ||
| 73 | |||
| 74 | #define CRC_LENGTH 2 | ||
| 75 | #define PPP_HEADER_LEN 4 | ||
| 76 | |||
| 77 | /******Data Structures*****************************************************/ | ||
| 78 | |||
| 79 | /* This structure is placed in the private data area of the device structure. | ||
| 80 | * The card structure used to occupy the private area but now the following | ||
| 81 | * structure will incorporate the card structure along with CHDLC specific data | ||
| 82 | */ | ||
| 83 | |||
| 84 | typedef struct chdlc_private_area | ||
| 85 | { | ||
| 86 | void *if_ptr; /* General Pointer used by SPPP */ | ||
| 87 | wanpipe_common_t common; | ||
| 88 | sdla_t *card; | ||
| 89 | int TracingEnabled; /* For enabling Tracing */ | ||
| 90 | unsigned long curr_trace_addr; /* Used for Tracing */ | ||
| 91 | unsigned long start_trace_addr; | ||
| 92 | unsigned long end_trace_addr; | ||
| 93 | unsigned long base_addr_trace_buffer; | ||
| 94 | unsigned long end_addr_trace_buffer; | ||
| 95 | unsigned short number_trace_elements; | ||
| 96 | unsigned available_buffer_space; | ||
| 97 | unsigned long router_start_time; | ||
| 98 | unsigned char route_status; | ||
| 99 | unsigned char route_removed; | ||
| 100 | unsigned long tick_counter; /* For 5s timeout counter */ | ||
| 101 | unsigned long router_up_time; | ||
| 102 | u32 IP_address; /* IP addressing */ | ||
| 103 | u32 IP_netmask; | ||
| 104 | unsigned char mc; /* Mulitcast support on/off */ | ||
| 105 | unsigned short udp_pkt_lgth; /* udp packet processing */ | ||
| 106 | char udp_pkt_src; | ||
| 107 | char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; | ||
| 108 | unsigned short timer_int_enabled; | ||
| 109 | char update_comms_stats; /* updating comms stats */ | ||
| 110 | |||
| 111 | //FIXME: add driver stats as per frame relay! | ||
| 112 | |||
| 113 | } chdlc_private_area_t; | ||
| 114 | |||
| 115 | /* Route Status options */ | ||
| 116 | #define NO_ROUTE 0x00 | ||
| 117 | #define ADD_ROUTE 0x01 | ||
| 118 | #define ROUTE_ADDED 0x02 | ||
| 119 | #define REMOVE_ROUTE 0x03 | ||
| 120 | |||
| 121 | |||
| 122 | /* variable for keeping track of enabling/disabling FT1 monitor status */ | ||
| 123 | static int rCount = 0; | ||
| 124 | |||
| 125 | /* variable for tracking how many interfaces to open for WANPIPE on the | ||
| 126 | two ports */ | ||
| 127 | |||
| 128 | extern void disable_irq(unsigned int); | ||
| 129 | extern void enable_irq(unsigned int); | ||
| 130 | |||
| 131 | /****** Function Prototypes *************************************************/ | ||
| 132 | /* WAN link driver entry points. These are called by the WAN router module. */ | ||
| 133 | static int update(struct wan_device* wandev); | ||
| 134 | static int new_if(struct wan_device* wandev, struct net_device* dev, | ||
| 135 | wanif_conf_t* conf); | ||
| 136 | static int del_if(struct wan_device* wandev, struct net_device* dev); | ||
| 137 | |||
| 138 | /* Network device interface */ | ||
| 139 | static int if_init(struct net_device* dev); | ||
| 140 | static int if_open(struct net_device* dev); | ||
| 141 | static int if_close(struct net_device* dev); | ||
| 142 | static int if_send(struct sk_buff* skb, struct net_device* dev); | ||
| 143 | static struct net_device_stats* if_stats(struct net_device* dev); | ||
| 144 | |||
| 145 | static void if_tx_timeout(struct net_device *dev); | ||
| 146 | |||
| 147 | /* CHDLC Firmware interface functions */ | ||
| 148 | static int chdlc_configure (sdla_t* card, void* data); | ||
| 149 | static int chdlc_comm_enable (sdla_t* card); | ||
| 150 | static int chdlc_comm_disable (sdla_t* card); | ||
| 151 | static int chdlc_read_version (sdla_t* card, char* str); | ||
| 152 | static int chdlc_set_intr_mode (sdla_t* card, unsigned mode); | ||
| 153 | static int chdlc_send (sdla_t* card, void* data, unsigned len); | ||
| 154 | static int chdlc_read_comm_err_stats (sdla_t* card); | ||
| 155 | static int chdlc_read_op_stats (sdla_t* card); | ||
| 156 | static int config_chdlc (sdla_t *card); | ||
| 157 | |||
| 158 | |||
| 159 | /* Miscellaneous CHDLC Functions */ | ||
| 160 | static int set_chdlc_config (sdla_t* card); | ||
| 161 | static void init_chdlc_tx_rx_buff(sdla_t* card, struct net_device *dev); | ||
| 162 | static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb); | ||
| 163 | static int process_chdlc_exception(sdla_t *card); | ||
| 164 | static int process_global_exception(sdla_t *card); | ||
| 165 | static int update_comms_stats(sdla_t* card, | ||
| 166 | chdlc_private_area_t* chdlc_priv_area); | ||
| 167 | static void port_set_state (sdla_t *card, int); | ||
| 168 | |||
| 169 | /* Interrupt handlers */ | ||
| 170 | static void wsppp_isr (sdla_t* card); | ||
| 171 | static void rx_intr (sdla_t* card); | ||
| 172 | static void timer_intr(sdla_t *); | ||
| 173 | |||
| 174 | /* Miscellaneous functions */ | ||
| 175 | static int reply_udp( unsigned char *data, unsigned int mbox_len ); | ||
| 176 | static int intr_test( sdla_t* card); | ||
| 177 | static int udp_pkt_type( struct sk_buff *skb , sdla_t* card); | ||
| 178 | static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, | ||
| 179 | struct sk_buff *skb, struct net_device* dev, | ||
| 180 | chdlc_private_area_t* chdlc_priv_area); | ||
| 181 | static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, | ||
| 182 | chdlc_private_area_t* chdlc_priv_area); | ||
| 183 | static unsigned short calc_checksum (char *, int); | ||
| 184 | static void s508_lock (sdla_t *card, unsigned long *smp_flags); | ||
| 185 | static void s508_unlock (sdla_t *card, unsigned long *smp_flags); | ||
| 186 | static void send_ppp_term_request(struct net_device *dev); | ||
| 187 | |||
| 188 | |||
| 189 | static int Intr_test_counter; | ||
| 190 | /****** Public Functions ****************************************************/ | ||
| 191 | |||
| 192 | /*============================================================================ | ||
| 193 | * Cisco HDLC protocol initialization routine. | ||
| 194 | * | ||
| 195 | * This routine is called by the main WANPIPE module during setup. At this | ||
| 196 | * point adapter is completely initialized and firmware is running. | ||
| 197 | * o read firmware version (to make sure it's alive) | ||
| 198 | * o configure adapter | ||
| 199 | * o initialize protocol-specific fields of the adapter data space. | ||
| 200 | * | ||
| 201 | * Return: 0 o.k. | ||
| 202 | * < 0 failure. | ||
| 203 | */ | ||
| 204 | int wsppp_init (sdla_t* card, wandev_conf_t* conf) | ||
| 205 | { | ||
| 206 | unsigned char port_num; | ||
| 207 | int err; | ||
| 208 | unsigned long max_permitted_baud = 0; | ||
| 209 | SHARED_MEMORY_INFO_STRUCT *flags; | ||
| 210 | |||
| 211 | union | ||
| 212 | { | ||
| 213 | char str[80]; | ||
| 214 | } u; | ||
| 215 | volatile CHDLC_MAILBOX_STRUCT* mb; | ||
| 216 | CHDLC_MAILBOX_STRUCT* mb1; | ||
| 217 | unsigned long timeout; | ||
| 218 | |||
| 219 | /* Verify configuration ID */ | ||
| 220 | if (conf->config_id != WANCONFIG_MPPP) { | ||
| 221 | printk(KERN_INFO "%s: invalid configuration ID %u!\n", | ||
| 222 | card->devname, conf->config_id); | ||
| 223 | return -EINVAL; | ||
| 224 | } | ||
| 225 | |||
| 226 | /* Find out which Port to use */ | ||
| 227 | if ((conf->comm_port == WANOPT_PRI) || (conf->comm_port == WANOPT_SEC)){ | ||
| 228 | if (card->next){ | ||
| 229 | |||
| 230 | if (conf->comm_port != card->next->u.c.comm_port){ | ||
| 231 | card->u.c.comm_port = conf->comm_port; | ||
| 232 | }else{ | ||
| 233 | printk(KERN_ERR "%s: ERROR - %s port used!\n", | ||
| 234 | card->wandev.name, PORT(conf->comm_port)); | ||
| 235 | return -EINVAL; | ||
| 236 | } | ||
| 237 | }else{ | ||
| 238 | card->u.c.comm_port = conf->comm_port; | ||
| 239 | } | ||
| 240 | }else{ | ||
| 241 | printk(KERN_ERR "%s: ERROR - Invalid Port Selected!\n", | ||
| 242 | card->wandev.name); | ||
| 243 | return -EINVAL; | ||
| 244 | } | ||
| 245 | |||
| 246 | |||
| 247 | /* Initialize protocol-specific fields */ | ||
| 248 | if(card->hw.type != SDLA_S514){ | ||
| 249 | |||
| 250 | if (card->u.c.comm_port == WANOPT_PRI){ | ||
| 251 | card->mbox = (void *) card->hw.dpmbase; | ||
| 252 | }else{ | ||
| 253 | card->mbox = (void *) card->hw.dpmbase + | ||
| 254 | SEC_BASE_ADDR_MB_STRUCT - PRI_BASE_ADDR_MB_STRUCT; | ||
| 255 | } | ||
| 256 | }else{ | ||
| 257 | /* for a S514 adapter, set a pointer to the actual mailbox in the */ | ||
| 258 | /* allocated virtual memory area */ | ||
| 259 | if (card->u.c.comm_port == WANOPT_PRI){ | ||
| 260 | card->mbox = (void *) card->hw.dpmbase + PRI_BASE_ADDR_MB_STRUCT; | ||
| 261 | }else{ | ||
| 262 | card->mbox = (void *) card->hw.dpmbase + SEC_BASE_ADDR_MB_STRUCT; | ||
| 263 | } | ||
| 264 | } | ||
| 265 | |||
| 266 | mb = mb1 = card->mbox; | ||
| 267 | |||
| 268 | if (!card->configured){ | ||
| 269 | |||
| 270 | /* The board will place an 'I' in the return code to indicate that it is | ||
| 271 | ready to accept commands. We expect this to be completed in less | ||
| 272 | than 1 second. */ | ||
| 273 | |||
| 274 | timeout = jiffies + 1 * HZ; | ||
| 275 | while (mb->return_code != 'I') /* Wait 1s for board to initialize */ | ||
| 276 | if (time_after(jiffies, timeout)) break; | ||
| 277 | |||
| 278 | if (mb->return_code != 'I') { | ||
| 279 | printk(KERN_INFO | ||
| 280 | "%s: Initialization not completed by adapter\n", | ||
| 281 | card->devname); | ||
| 282 | printk(KERN_INFO "Please contact Sangoma representative.\n"); | ||
| 283 | return -EIO; | ||
| 284 | } | ||
| 285 | } | ||
| 286 | |||
| 287 | /* Read firmware version. Note that when adapter initializes, it | ||
| 288 | * clears the mailbox, so it may appear that the first command was | ||
| 289 | * executed successfully when in fact it was merely erased. To work | ||
| 290 | * around this, we execute the first command twice. | ||
| 291 | */ | ||
| 292 | |||
| 293 | if (chdlc_read_version(card, u.str)) | ||
| 294 | return -EIO; | ||
| 295 | |||
| 296 | printk(KERN_INFO "%s: Running Raw CHDLC firmware v%s\n" | ||
| 297 | "%s: for Multi-Port PPP protocol.\n", | ||
| 298 | card->devname,u.str,card->devname); | ||
| 299 | |||
| 300 | card->isr = &wsppp_isr; | ||
| 301 | card->poll = NULL; | ||
| 302 | card->exec = NULL; | ||
| 303 | card->wandev.update = &update; | ||
| 304 | card->wandev.new_if = &new_if; | ||
| 305 | card->wandev.del_if = &del_if; | ||
| 306 | card->wandev.udp_port = conf->udp_port; | ||
| 307 | |||
| 308 | card->wandev.new_if_cnt = 0; | ||
| 309 | |||
| 310 | /* reset the number of times the 'update()' proc has been called */ | ||
| 311 | card->u.c.update_call_count = 0; | ||
| 312 | |||
| 313 | card->wandev.ttl = conf->ttl; | ||
| 314 | card->wandev.interface = conf->interface; | ||
| 315 | |||
| 316 | if ((card->u.c.comm_port == WANOPT_SEC && conf->interface == WANOPT_V35)&& | ||
| 317 | card->hw.type != SDLA_S514){ | ||
| 318 | printk(KERN_INFO "%s: ERROR - V35 Interface not supported on S508 %s port \n", | ||
| 319 | card->devname, PORT(card->u.c.comm_port)); | ||
| 320 | return -EIO; | ||
| 321 | } | ||
| 322 | |||
| 323 | |||
| 324 | card->wandev.clocking = conf->clocking; | ||
| 325 | |||
| 326 | port_num = card->u.c.comm_port; | ||
| 327 | |||
| 328 | /* Setup Port Bps */ | ||
| 329 | |||
| 330 | if(card->wandev.clocking) { | ||
| 331 | if((port_num == WANOPT_PRI) || card->u.c.receive_only) { | ||
| 332 | /* For Primary Port 0 */ | ||
| 333 | max_permitted_baud = | ||
| 334 | (card->hw.type == SDLA_S514) ? | ||
| 335 | PRI_MAX_BAUD_RATE_S514 : | ||
| 336 | PRI_MAX_BAUD_RATE_S508; | ||
| 337 | } | ||
| 338 | else if(port_num == WANOPT_SEC) { | ||
| 339 | /* For Secondary Port 1 */ | ||
| 340 | max_permitted_baud = | ||
| 341 | (card->hw.type == SDLA_S514) ? | ||
| 342 | SEC_MAX_BAUD_RATE_S514 : | ||
| 343 | SEC_MAX_BAUD_RATE_S508; | ||
| 344 | } | ||
| 345 | |||
| 346 | if(conf->bps > max_permitted_baud) { | ||
| 347 | conf->bps = max_permitted_baud; | ||
| 348 | printk(KERN_INFO "%s: Baud too high!\n", | ||
| 349 | card->wandev.name); | ||
| 350 | printk(KERN_INFO "%s: Baud rate set to %lu bps\n", | ||
| 351 | card->wandev.name, max_permitted_baud); | ||
| 352 | } | ||
| 353 | |||
| 354 | card->wandev.bps = conf->bps; | ||
| 355 | }else{ | ||
| 356 | card->wandev.bps = 0; | ||
| 357 | } | ||
| 358 | |||
| 359 | /* Setup the Port MTU */ | ||
| 360 | if((port_num == WANOPT_PRI) || card->u.c.receive_only) { | ||
| 361 | |||
| 362 | /* For Primary Port 0 */ | ||
| 363 | card->wandev.mtu = | ||
| 364 | (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? | ||
| 365 | min_t(unsigned int, conf->mtu, PRI_MAX_NO_DATA_BYTES_IN_FRAME) : | ||
| 366 | CHDLC_DFLT_DATA_LEN; | ||
| 367 | } else if(port_num == WANOPT_SEC) { | ||
| 368 | /* For Secondary Port 1 */ | ||
| 369 | card->wandev.mtu = | ||
| 370 | (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? | ||
| 371 | min_t(unsigned int, conf->mtu, SEC_MAX_NO_DATA_BYTES_IN_FRAME) : | ||
| 372 | CHDLC_DFLT_DATA_LEN; | ||
| 373 | } | ||
| 374 | |||
| 375 | /* Add on a PPP Header */ | ||
| 376 | card->wandev.mtu += PPP_HEADER_LEN; | ||
| 377 | |||
| 378 | /* Set up the interrupt status area */ | ||
| 379 | /* Read the CHDLC Configuration and obtain: | ||
| 380 | * Ptr to shared memory infor struct | ||
| 381 | * Use this pointer to calculate the value of card->u.c.flags ! | ||
| 382 | */ | ||
| 383 | mb1->buffer_length = 0; | ||
| 384 | mb1->command = READ_CHDLC_CONFIGURATION; | ||
| 385 | err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT; | ||
| 386 | if(err != COMMAND_OK) { | ||
| 387 | clear_bit(1, (void*)&card->wandev.critical); | ||
| 388 | |||
| 389 | if(card->hw.type != SDLA_S514) | ||
| 390 | enable_irq(card->hw.irq); | ||
| 391 | |||
| 392 | chdlc_error(card, err, mb1); | ||
| 393 | return -EIO; | ||
| 394 | } | ||
| 395 | |||
| 396 | if(card->hw.type == SDLA_S514){ | ||
| 397 | card->u.c.flags = (void *)(card->hw.dpmbase + | ||
| 398 | (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> | ||
| 399 | ptr_shared_mem_info_struct)); | ||
| 400 | }else{ | ||
| 401 | card->u.c.flags = (void *)(card->hw.dpmbase + | ||
| 402 | (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> | ||
| 403 | ptr_shared_mem_info_struct % SDLA_WINDOWSIZE)); | ||
| 404 | } | ||
| 405 | |||
| 406 | flags = card->u.c.flags; | ||
| 407 | |||
| 408 | /* This is for the ports link state */ | ||
| 409 | card->wandev.state = WAN_DUALPORT; | ||
| 410 | card->u.c.state = WAN_DISCONNECTED; | ||
| 411 | |||
| 412 | |||
| 413 | if (!card->wandev.piggyback){ | ||
| 414 | err = intr_test(card); | ||
| 415 | |||
| 416 | if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { | ||
| 417 | printk(KERN_ERR "%s: Interrupt test failed (%i)\n", | ||
| 418 | card->devname, Intr_test_counter); | ||
| 419 | printk(KERN_ERR "%s: Please choose another interrupt\n", | ||
| 420 | card->devname); | ||
| 421 | return -EIO; | ||
| 422 | } | ||
| 423 | |||
| 424 | printk(KERN_INFO "%s: Interrupt test passed (%i)\n", | ||
| 425 | card->devname, Intr_test_counter); | ||
| 426 | } | ||
| 427 | |||
| 428 | |||
| 429 | if (chdlc_set_intr_mode(card, APP_INT_ON_TIMER)){ | ||
| 430 | printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", | ||
| 431 | card->devname); | ||
| 432 | return -EIO; | ||
| 433 | } | ||
| 434 | |||
| 435 | /* Mask the Timer interrupt */ | ||
| 436 | flags->interrupt_info_struct.interrupt_permission &= | ||
| 437 | ~APP_INT_ON_TIMER; | ||
| 438 | |||
| 439 | printk(KERN_INFO "\n"); | ||
| 440 | |||
| 441 | return 0; | ||
| 442 | } | ||
| 443 | |||
| 444 | /******* WAN Device Driver Entry Points *************************************/ | ||
| 445 | |||
| 446 | /*============================================================================ | ||
| 447 | * Update device status & statistics | ||
| 448 | * This procedure is called when updating the PROC file system and returns | ||
| 449 | * various communications statistics. These statistics are accumulated from 3 | ||
| 450 | * different locations: | ||
| 451 | * 1) The 'if_stats' recorded for the device. | ||
| 452 | * 2) Communication error statistics on the adapter. | ||
| 453 | * 3) CHDLC operational statistics on the adapter. | ||
| 454 | * The board level statistics are read during a timer interrupt. Note that we | ||
| 455 | * read the error and operational statistics during consecitive timer ticks so | ||
| 456 | * as to minimize the time that we are inside the interrupt handler. | ||
| 457 | * | ||
| 458 | */ | ||
| 459 | static int update(struct wan_device* wandev) | ||
| 460 | { | ||
| 461 | sdla_t* card = wandev->private; | ||
| 462 | struct net_device* dev; | ||
| 463 | volatile chdlc_private_area_t* chdlc_priv_area; | ||
| 464 | SHARED_MEMORY_INFO_STRUCT *flags; | ||
| 465 | unsigned long timeout; | ||
| 466 | |||
| 467 | /* sanity checks */ | ||
| 468 | if((wandev == NULL) || (wandev->private == NULL)) | ||
| 469 | return -EFAULT; | ||
| 470 | |||
| 471 | if(wandev->state == WAN_UNCONFIGURED) | ||
| 472 | return -ENODEV; | ||
| 473 | |||
| 474 | /* more sanity checks */ | ||
| 475 | if(!card->u.c.flags) | ||
| 476 | return -ENODEV; | ||
| 477 | |||
| 478 | if((dev=card->wandev.dev) == NULL) | ||
| 479 | return -ENODEV; | ||
| 480 | |||
| 481 | if((chdlc_priv_area=dev->priv) == NULL) | ||
| 482 | return -ENODEV; | ||
| 483 | |||
| 484 | flags = card->u.c.flags; | ||
| 485 | |||
| 486 | if(chdlc_priv_area->update_comms_stats){ | ||
| 487 | return -EAGAIN; | ||
| 488 | } | ||
| 489 | |||
| 490 | /* we will need 2 timer interrupts to complete the */ | ||
| 491 | /* reading of the statistics */ | ||
| 492 | chdlc_priv_area->update_comms_stats = 2; | ||
| 493 | flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; | ||
| 494 | chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UPDATE; | ||
| 495 | |||
| 496 | /* wait a maximum of 1 second for the statistics to be updated */ | ||
| 497 | timeout = jiffies + 1 * HZ; | ||
| 498 | for(;;) { | ||
| 499 | if(chdlc_priv_area->update_comms_stats == 0) | ||
| 500 | break; | ||
| 501 | if (time_after(jiffies, timeout)){ | ||
| 502 | chdlc_priv_area->update_comms_stats = 0; | ||
| 503 | chdlc_priv_area->timer_int_enabled &= | ||
| 504 | ~TMR_INT_ENABLED_UPDATE; | ||
| 505 | return -EAGAIN; | ||
| 506 | } | ||
| 507 | } | ||
| 508 | |||
| 509 | return 0; | ||
| 510 | } | ||
| 511 | |||
| 512 | |||
| 513 | /*============================================================================ | ||
| 514 | * Create new logical channel. | ||
| 515 | * This routine is called by the router when ROUTER_IFNEW IOCTL is being | ||
| 516 | * handled. | ||
| 517 | * o parse media- and hardware-specific configuration | ||
| 518 | * o make sure that a new channel can be created | ||
| 519 | * o allocate resources, if necessary | ||
| 520 | * o prepare network device structure for registaration. | ||
| 521 | * | ||
| 522 | * Return: 0 o.k. | ||
| 523 | * < 0 failure (channel will not be created) | ||
| 524 | */ | ||
| 525 | static int new_if(struct wan_device* wandev, struct net_device* pdev, | ||
| 526 | wanif_conf_t* conf) | ||
| 527 | { | ||
| 528 | |||
| 529 | struct ppp_device *pppdev = (struct ppp_device *)pdev; | ||
| 530 | struct net_device *dev = NULL; | ||
| 531 | struct sppp *sp; | ||
| 532 | sdla_t* card = wandev->private; | ||
| 533 | chdlc_private_area_t* chdlc_priv_area; | ||
| 534 | |||
| 535 | if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { | ||
| 536 | printk(KERN_INFO "%s: invalid interface name!\n", | ||
| 537 | card->devname); | ||
| 538 | return -EINVAL; | ||
| 539 | } | ||
| 540 | |||
| 541 | /* allocate and initialize private data */ | ||
| 542 | chdlc_priv_area = kmalloc(sizeof(chdlc_private_area_t), GFP_KERNEL); | ||
| 543 | |||
| 544 | if(chdlc_priv_area == NULL) | ||
| 545 | return -ENOMEM; | ||
| 546 | |||
| 547 | memset(chdlc_priv_area, 0, sizeof(chdlc_private_area_t)); | ||
| 548 | |||
| 549 | chdlc_priv_area->card = card; | ||
| 550 | |||
| 551 | /* initialize data */ | ||
| 552 | strcpy(card->u.c.if_name, conf->name); | ||
| 553 | |||
| 554 | if(card->wandev.new_if_cnt > 0) { | ||
| 555 | kfree(chdlc_priv_area); | ||
| 556 | return -EEXIST; | ||
| 557 | } | ||
| 558 | |||
| 559 | card->wandev.new_if_cnt++; | ||
| 560 | |||
| 561 | chdlc_priv_area->TracingEnabled = 0; | ||
| 562 | |||
| 563 | //We don't need this any more | ||
| 564 | chdlc_priv_area->route_status = NO_ROUTE; | ||
| 565 | chdlc_priv_area->route_removed = 0; | ||
| 566 | |||
| 567 | printk(KERN_INFO "%s: Firmware running in HDLC STREAMING Mode\n", | ||
| 568 | wandev->name); | ||
| 569 | |||
| 570 | /* Setup wanpipe as a router (WANPIPE) or as an API */ | ||
| 571 | if( strcmp(conf->usedby, "WANPIPE") == 0) { | ||
| 572 | printk(KERN_INFO "%s: Driver running in WANPIPE mode!\n", | ||
| 573 | wandev->name); | ||
| 574 | card->u.c.usedby = WANPIPE; | ||
| 575 | } else { | ||
| 576 | printk(KERN_INFO | ||
| 577 | "%s: API Mode is not supported for SyncPPP!\n", | ||
| 578 | wandev->name); | ||
| 579 | kfree(chdlc_priv_area); | ||
| 580 | return -EINVAL; | ||
| 581 | } | ||
| 582 | |||
| 583 | /* Get Multicast Information */ | ||
| 584 | chdlc_priv_area->mc = conf->mc; | ||
| 585 | |||
| 586 | |||
| 587 | chdlc_priv_area->if_ptr = pppdev; | ||
| 588 | |||
| 589 | /* prepare network device data space for registration */ | ||
| 590 | |||
| 591 | strcpy(dev->name,card->u.c.if_name); | ||
| 592 | |||
| 593 | /* Attach PPP protocol layer to pppdev | ||
| 594 | * The sppp_attach() will initilize the dev structure | ||
| 595 | * and setup ppp layer protocols. | ||
| 596 | * All we have to do is to bind in: | ||
| 597 | * if_open(), if_close(), if_send() and get_stats() functions. | ||
| 598 | */ | ||
| 599 | sppp_attach(pppdev); | ||
| 600 | dev = pppdev->dev; | ||
| 601 | sp = &pppdev->sppp; | ||
| 602 | |||
| 603 | /* Enable PPP Debugging */ | ||
| 604 | // FIXME Fix this up somehow | ||
| 605 | //sp->pp_flags |= PP_DEBUG; | ||
| 606 | sp->pp_flags &= ~PP_CISCO; | ||
| 607 | |||
| 608 | dev->init = &if_init; | ||
| 609 | dev->priv = chdlc_priv_area; | ||
| 610 | |||
| 611 | return 0; | ||
| 612 | } | ||
| 613 | |||
| 614 | |||
| 615 | |||
| 616 | |||
| 617 | /*============================================================================ | ||
| 618 | * Delete logical channel. | ||
| 619 | */ | ||
| 620 | static int del_if(struct wan_device* wandev, struct net_device* dev) | ||
| 621 | { | ||
| 622 | chdlc_private_area_t *chdlc_priv_area = dev->priv; | ||
| 623 | sdla_t *card = chdlc_priv_area->card; | ||
| 624 | unsigned long smp_lock; | ||
| 625 | |||
| 626 | /* Detach the PPP layer */ | ||
| 627 | printk(KERN_INFO "%s: Detaching SyncPPP Module from %s\n", | ||
| 628 | wandev->name,dev->name); | ||
| 629 | |||
| 630 | lock_adapter_irq(&wandev->lock,&smp_lock); | ||
| 631 | |||
| 632 | sppp_detach(dev); | ||
| 633 | chdlc_priv_area->if_ptr=NULL; | ||
| 634 | |||
| 635 | chdlc_set_intr_mode(card, 0); | ||
| 636 | if (card->u.c.comm_enabled) | ||
| 637 | chdlc_comm_disable(card); | ||
| 638 | unlock_adapter_irq(&wandev->lock,&smp_lock); | ||
| 639 | |||
| 640 | port_set_state(card, WAN_DISCONNECTED); | ||
| 641 | |||
| 642 | return 0; | ||
| 643 | } | ||
| 644 | |||
| 645 | |||
| 646 | /****** Network Device Interface ********************************************/ | ||
| 647 | |||
| 648 | /*============================================================================ | ||
| 649 | * Initialize Linux network interface. | ||
| 650 | * | ||
| 651 | * This routine is called only once for each interface, during Linux network | ||
| 652 | * interface registration. Returning anything but zero will fail interface | ||
| 653 | * registration. | ||
| 654 | */ | ||
| 655 | static int if_init(struct net_device* dev) | ||
| 656 | { | ||
| 657 | chdlc_private_area_t* chdlc_priv_area = dev->priv; | ||
| 658 | sdla_t* card = chdlc_priv_area->card; | ||
| 659 | struct wan_device* wandev = &card->wandev; | ||
| 660 | |||
| 661 | /* NOTE: Most of the dev initialization was | ||
| 662 | * done in sppp_attach(), called by new_if() | ||
| 663 | * function. All we have to do here is | ||
| 664 | * to link four major routines below. | ||
| 665 | */ | ||
| 666 | |||
| 667 | /* Initialize device driver entry points */ | ||
| 668 | dev->open = &if_open; | ||
| 669 | dev->stop = &if_close; | ||
| 670 | dev->hard_start_xmit = &if_send; | ||
| 671 | dev->get_stats = &if_stats; | ||
| 672 | dev->tx_timeout = &if_tx_timeout; | ||
| 673 | dev->watchdog_timeo = TX_TIMEOUT; | ||
| 674 | |||
| 675 | |||
| 676 | /* Initialize hardware parameters */ | ||
| 677 | dev->irq = wandev->irq; | ||
| 678 | dev->dma = wandev->dma; | ||
| 679 | dev->base_addr = wandev->ioport; | ||
| 680 | dev->mem_start = wandev->maddr; | ||
| 681 | dev->mem_end = wandev->maddr + wandev->msize - 1; | ||
| 682 | |||
| 683 | /* Set transmit buffer queue length | ||
| 684 | * If we over fill this queue the packets will | ||
| 685 | * be droped by the kernel. | ||
| 686 | * sppp_attach() sets this to 10, but | ||
| 687 | * 100 will give us more room at low speeds. | ||
| 688 | */ | ||
| 689 | dev->tx_queue_len = 100; | ||
| 690 | |||
| 691 | return 0; | ||
| 692 | } | ||
| 693 | |||
| 694 | |||
| 695 | /*============================================================================ | ||
| 696 | * Handle transmit timeout event from netif watchdog | ||
| 697 | */ | ||
| 698 | static void if_tx_timeout(struct net_device *dev) | ||
| 699 | { | ||
| 700 | chdlc_private_area_t* chan = dev->priv; | ||
| 701 | sdla_t *card = chan->card; | ||
| 702 | |||
| 703 | /* If our device stays busy for at least 5 seconds then we will | ||
| 704 | * kick start the device by making dev->tbusy = 0. We expect | ||
| 705 | * that our device never stays busy more than 5 seconds. So this | ||
| 706 | * is only used as a last resort. | ||
| 707 | */ | ||
| 708 | |||
| 709 | ++card->wandev.stats.collisions; | ||
| 710 | |||
| 711 | printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); | ||
| 712 | netif_wake_queue (dev); | ||
| 713 | } | ||
| 714 | |||
| 715 | |||
| 716 | /*============================================================================ | ||
| 717 | * Open network interface. | ||
| 718 | * o enable communications and interrupts. | ||
| 719 | * o prevent module from unloading by incrementing use count | ||
| 720 | * | ||
| 721 | * Return 0 if O.k. or errno. | ||
| 722 | */ | ||
| 723 | static int if_open(struct net_device* dev) | ||
| 724 | { | ||
| 725 | chdlc_private_area_t* chdlc_priv_area = dev->priv; | ||
| 726 | sdla_t* card = chdlc_priv_area->card; | ||
| 727 | struct timeval tv; | ||
| 728 | SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; | ||
| 729 | |||
| 730 | /* Only one open per interface is allowed */ | ||
| 731 | if (netif_running(dev)) | ||
| 732 | return -EBUSY; | ||
| 733 | |||
| 734 | /* Start PPP Layer */ | ||
| 735 | if (sppp_open(dev)){ | ||
| 736 | return -EIO; | ||
| 737 | } | ||
| 738 | |||
| 739 | do_gettimeofday(&tv); | ||
| 740 | chdlc_priv_area->router_start_time = tv.tv_sec; | ||
| 741 | |||
| 742 | netif_start_queue(dev); | ||
| 743 | |||
| 744 | wanpipe_open(card); | ||
| 745 | |||
| 746 | chdlc_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG; | ||
| 747 | flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; | ||
| 748 | return 0; | ||
| 749 | } | ||
| 750 | |||
| 751 | /*============================================================================ | ||
| 752 | * Close network interface. | ||
| 753 | * o if this is the last close, then disable communications and interrupts. | ||
| 754 | * o reset flags. | ||
| 755 | */ | ||
| 756 | static int if_close(struct net_device* dev) | ||
| 757 | { | ||
| 758 | chdlc_private_area_t* chdlc_priv_area = dev->priv; | ||
| 759 | sdla_t* card = chdlc_priv_area->card; | ||
| 760 | |||
| 761 | /* Stop the PPP Layer */ | ||
| 762 | sppp_close(dev); | ||
| 763 | netif_stop_queue(dev); | ||
| 764 | |||
| 765 | wanpipe_close(card); | ||
| 766 | |||
| 767 | return 0; | ||
| 768 | } | ||
| 769 | |||
| 770 | /*============================================================================ | ||
| 771 | * Send a packet on a network interface. | ||
| 772 | * o set tbusy flag (marks start of the transmission) to block a timer-based | ||
| 773 | * transmit from overlapping. | ||
| 774 | * o check link state. If link is not up, then drop the packet. | ||
| 775 | * o execute adapter send command. | ||
| 776 | * o free socket buffer | ||
| 777 | * | ||
| 778 | * Return: 0 complete (socket buffer must be freed) | ||
| 779 | * non-0 packet may be re-transmitted (tbusy must be set) | ||
| 780 | * | ||
| 781 | * Notes: | ||
| 782 | * 1. This routine is called either by the protocol stack or by the "net | ||
| 783 | * bottom half" (with interrupts enabled). | ||
| 784 | * 2. Setting tbusy flag will inhibit further transmit requests from the | ||
| 785 | * protocol stack and can be used for flow control with protocol layer. | ||
| 786 | */ | ||
| 787 | static int if_send(struct sk_buff* skb, struct net_device* dev) | ||
| 788 | { | ||
| 789 | chdlc_private_area_t *chdlc_priv_area = dev->priv; | ||
| 790 | sdla_t *card = chdlc_priv_area->card; | ||
| 791 | SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; | ||
| 792 | INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct; | ||
| 793 | int udp_type = 0; | ||
| 794 | unsigned long smp_flags; | ||
| 795 | int err=0; | ||
| 796 | |||
| 797 | netif_stop_queue(dev); | ||
| 798 | |||
| 799 | |||
| 800 | if (skb == NULL){ | ||
| 801 | /* If we get here, some higher layer thinks we've missed an | ||
| 802 | * tx-done interrupt. | ||
| 803 | */ | ||
| 804 | printk(KERN_INFO "%s: Received NULL skb buffer! interface %s got kicked!\n", | ||
| 805 | card->devname, dev->name); | ||
| 806 | |||
| 807 | netif_wake_queue(dev); | ||
| 808 | return 0; | ||
| 809 | } | ||
| 810 | |||
| 811 | if (ntohs(skb->protocol) != htons(PVC_PROT)){ | ||
| 812 | /* check the udp packet type */ | ||
| 813 | |||
| 814 | udp_type = udp_pkt_type(skb, card); | ||
| 815 | if (udp_type == UDP_CPIPE_TYPE){ | ||
| 816 | if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, | ||
| 817 | chdlc_priv_area)){ | ||
| 818 | chdlc_int->interrupt_permission |= | ||
| 819 | APP_INT_ON_TIMER; | ||
| 820 | } | ||
| 821 | netif_start_queue(dev); | ||
| 822 | return 0; | ||
| 823 | } | ||
| 824 | } | ||
| 825 | |||
| 826 | /* Lock the 508 Card: SMP is supported */ | ||
| 827 | if(card->hw.type != SDLA_S514){ | ||
| 828 | s508_lock(card,&smp_flags); | ||
| 829 | } | ||
| 830 | |||
| 831 | if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)){ | ||
| 832 | |||
| 833 | printk(KERN_INFO "%s: Critical in if_send: %lx\n", | ||
| 834 | card->wandev.name,card->wandev.critical); | ||
| 835 | ++card->wandev.stats.tx_dropped; | ||
| 836 | netif_start_queue(dev); | ||
| 837 | goto if_send_crit_exit; | ||
| 838 | } | ||
| 839 | |||
| 840 | if (card->wandev.state != WAN_CONNECTED){ | ||
| 841 | ++card->wandev.stats.tx_dropped; | ||
| 842 | netif_start_queue(dev); | ||
| 843 | goto if_send_crit_exit; | ||
| 844 | } | ||
| 845 | |||
| 846 | if (chdlc_send(card, skb->data, skb->len)){ | ||
| 847 | netif_stop_queue(dev); | ||
| 848 | |||
| 849 | }else{ | ||
| 850 | ++card->wandev.stats.tx_packets; | ||
| 851 | card->wandev.stats.tx_bytes += skb->len; | ||
| 852 | dev->trans_start = jiffies; | ||
| 853 | netif_start_queue(dev); | ||
| 854 | } | ||
| 855 | |||
| 856 | if_send_crit_exit: | ||
| 857 | if (!(err=netif_queue_stopped(dev))){ | ||
| 858 | dev_kfree_skb_any(skb); | ||
| 859 | }else{ | ||
| 860 | chdlc_priv_area->tick_counter = jiffies; | ||
| 861 | chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME; | ||
| 862 | } | ||
| 863 | |||
| 864 | clear_bit(SEND_CRIT, (void*)&card->wandev.critical); | ||
| 865 | if(card->hw.type != SDLA_S514){ | ||
| 866 | s508_unlock(card,&smp_flags); | ||
| 867 | } | ||
| 868 | |||
| 869 | return err; | ||
| 870 | } | ||
| 871 | |||
| 872 | |||
| 873 | /*============================================================================ | ||
| 874 | * Reply to UDP Management system. | ||
| 875 | * Return length of reply. | ||
| 876 | */ | ||
| 877 | static int reply_udp( unsigned char *data, unsigned int mbox_len ) | ||
| 878 | { | ||
| 879 | |||
| 880 | unsigned short len, udp_length, temp, ip_length; | ||
| 881 | unsigned long ip_temp; | ||
| 882 | int even_bound = 0; | ||
| 883 | chdlc_udp_pkt_t *c_udp_pkt = (chdlc_udp_pkt_t *)data; | ||
| 884 | |||
| 885 | /* Set length of packet */ | ||
| 886 | len = sizeof(ip_pkt_t)+ | ||
| 887 | sizeof(udp_pkt_t)+ | ||
| 888 | sizeof(wp_mgmt_t)+ | ||
| 889 | sizeof(cblock_t)+ | ||
| 890 | sizeof(trace_info_t)+ | ||
| 891 | mbox_len; | ||
| 892 | |||
| 893 | /* fill in UDP reply */ | ||
| 894 | c_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; | ||
| 895 | |||
| 896 | /* fill in UDP length */ | ||
| 897 | udp_length = sizeof(udp_pkt_t)+ | ||
| 898 | sizeof(wp_mgmt_t)+ | ||
| 899 | sizeof(cblock_t)+ | ||
| 900 | sizeof(trace_info_t)+ | ||
| 901 | mbox_len; | ||
| 902 | |||
| 903 | /* put it on an even boundary */ | ||
| 904 | if ( udp_length & 0x0001 ) { | ||
| 905 | udp_length += 1; | ||
| 906 | len += 1; | ||
| 907 | even_bound = 1; | ||
| 908 | } | ||
| 909 | |||
| 910 | temp = (udp_length<<8)|(udp_length>>8); | ||
| 911 | c_udp_pkt->udp_pkt.udp_length = temp; | ||
| 912 | |||
| 913 | /* swap UDP ports */ | ||
| 914 | temp = c_udp_pkt->udp_pkt.udp_src_port; | ||
| 915 | c_udp_pkt->udp_pkt.udp_src_port = | ||
| 916 | c_udp_pkt->udp_pkt.udp_dst_port; | ||
| 917 | c_udp_pkt->udp_pkt.udp_dst_port = temp; | ||
| 918 | |||
| 919 | /* add UDP pseudo header */ | ||
| 920 | temp = 0x1100; | ||
| 921 | *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound)) = temp; | ||
| 922 | temp = (udp_length<<8)|(udp_length>>8); | ||
| 923 | *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound+2)) = temp; | ||
| 924 | |||
| 925 | |||
| 926 | /* calculate UDP checksum */ | ||
| 927 | c_udp_pkt->udp_pkt.udp_checksum = 0; | ||
| 928 | c_udp_pkt->udp_pkt.udp_checksum = calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET); | ||
| 929 | |||
| 930 | /* fill in IP length */ | ||
| 931 | ip_length = len; | ||
| 932 | temp = (ip_length<<8)|(ip_length>>8); | ||
| 933 | c_udp_pkt->ip_pkt.total_length = temp; | ||
| 934 | |||
| 935 | /* swap IP addresses */ | ||
| 936 | ip_temp = c_udp_pkt->ip_pkt.ip_src_address; | ||
| 937 | c_udp_pkt->ip_pkt.ip_src_address = c_udp_pkt->ip_pkt.ip_dst_address; | ||
| 938 | c_udp_pkt->ip_pkt.ip_dst_address = ip_temp; | ||
| 939 | |||
| 940 | /* fill in IP checksum */ | ||
| 941 | c_udp_pkt->ip_pkt.hdr_checksum = 0; | ||
| 942 | c_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data,sizeof(ip_pkt_t)); | ||
| 943 | |||
| 944 | return len; | ||
| 945 | |||
| 946 | } /* reply_udp */ | ||
| 947 | |||
| 948 | unsigned short calc_checksum (char *data, int len) | ||
| 949 | { | ||
| 950 | unsigned short temp; | ||
| 951 | unsigned long sum=0; | ||
| 952 | int i; | ||
| 953 | |||
| 954 | for( i = 0; i <len; i+=2 ) { | ||
| 955 | memcpy(&temp,&data[i],2); | ||
| 956 | sum += (unsigned long)temp; | ||
| 957 | } | ||
| 958 | |||
| 959 | while (sum >> 16 ) { | ||
| 960 | sum = (sum & 0xffffUL) + (sum >> 16); | ||
| 961 | } | ||
| 962 | |||
| 963 | temp = (unsigned short)sum; | ||
| 964 | temp = ~temp; | ||
| 965 | |||
| 966 | if( temp == 0 ) | ||
| 967 | temp = 0xffff; | ||
| 968 | |||
| 969 | return temp; | ||
| 970 | } | ||
| 971 | |||
| 972 | |||
| 973 | /*============================================================================ | ||
| 974 | * Get ethernet-style interface statistics. | ||
| 975 | * Return a pointer to struct enet_statistics. | ||
| 976 | */ | ||
| 977 | static struct net_device_stats* if_stats(struct net_device* dev) | ||
| 978 | { | ||
| 979 | sdla_t *my_card; | ||
| 980 | chdlc_private_area_t* chdlc_priv_area; | ||
| 981 | |||
| 982 | /* Shutdown bug fix. In del_if() we kill | ||
| 983 | * dev->priv pointer. This function, gets | ||
| 984 | * called after del_if(), thus check | ||
| 985 | * if pointer has been deleted */ | ||
| 986 | if ((chdlc_priv_area=dev->priv) == NULL) | ||
| 987 | return NULL; | ||
| 988 | |||
| 989 | my_card = chdlc_priv_area->card; | ||
| 990 | return &my_card->wandev.stats; | ||
| 991 | } | ||
| 992 | |||
| 993 | |||
| 994 | /****** Cisco HDLC Firmware Interface Functions *******************************/ | ||
| 995 | |||
| 996 | /*============================================================================ | ||
| 997 | * Read firmware code version. | ||
| 998 | * Put code version as ASCII string in str. | ||
| 999 | */ | ||
| 1000 | static int chdlc_read_version (sdla_t* card, char* str) | ||
| 1001 | { | ||
| 1002 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
| 1003 | int len; | ||
| 1004 | char err; | ||
| 1005 | mb->buffer_length = 0; | ||
| 1006 | mb->command = READ_CHDLC_CODE_VERSION; | ||
| 1007 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 1008 | |||
| 1009 | if(err != COMMAND_OK) { | ||
| 1010 | chdlc_error(card,err,mb); | ||
| 1011 | } | ||
| 1012 | else if (str) { /* is not null */ | ||
| 1013 | len = mb->buffer_length; | ||
| 1014 | memcpy(str, mb->data, len); | ||
| 1015 | str[len] = '\0'; | ||
| 1016 | } | ||
| 1017 | return (err); | ||
| 1018 | } | ||
| 1019 | |||
| 1020 | /*----------------------------------------------------------------------------- | ||
| 1021 | * Configure CHDLC firmware. | ||
| 1022 | */ | ||
| 1023 | static int chdlc_configure (sdla_t* card, void* data) | ||
| 1024 | { | ||
| 1025 | int err; | ||
| 1026 | CHDLC_MAILBOX_STRUCT *mailbox = card->mbox; | ||
| 1027 | int data_length = sizeof(CHDLC_CONFIGURATION_STRUCT); | ||
| 1028 | |||
| 1029 | mailbox->buffer_length = data_length; | ||
| 1030 | memcpy(mailbox->data, data, data_length); | ||
| 1031 | mailbox->command = SET_CHDLC_CONFIGURATION; | ||
| 1032 | err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT; | ||
| 1033 | |||
| 1034 | if (err != COMMAND_OK) chdlc_error (card, err, mailbox); | ||
| 1035 | |||
| 1036 | return err; | ||
| 1037 | } | ||
| 1038 | |||
| 1039 | |||
| 1040 | /*============================================================================ | ||
| 1041 | * Set interrupt mode -- HDLC Version. | ||
| 1042 | */ | ||
| 1043 | |||
| 1044 | static int chdlc_set_intr_mode (sdla_t* card, unsigned mode) | ||
| 1045 | { | ||
| 1046 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
| 1047 | CHDLC_INT_TRIGGERS_STRUCT* int_data = | ||
| 1048 | (CHDLC_INT_TRIGGERS_STRUCT *)mb->data; | ||
| 1049 | int err; | ||
| 1050 | |||
| 1051 | int_data->CHDLC_interrupt_triggers = mode; | ||
| 1052 | int_data->IRQ = card->hw.irq; | ||
| 1053 | int_data->interrupt_timer = 1; | ||
| 1054 | |||
| 1055 | mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT); | ||
| 1056 | mb->command = SET_CHDLC_INTERRUPT_TRIGGERS; | ||
| 1057 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 1058 | if (err != COMMAND_OK) | ||
| 1059 | chdlc_error (card, err, mb); | ||
| 1060 | return err; | ||
| 1061 | } | ||
| 1062 | |||
| 1063 | |||
| 1064 | /*============================================================================ | ||
| 1065 | * Enable communications. | ||
| 1066 | */ | ||
| 1067 | |||
| 1068 | static int chdlc_comm_enable (sdla_t* card) | ||
| 1069 | { | ||
| 1070 | int err; | ||
| 1071 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
| 1072 | |||
| 1073 | mb->buffer_length = 0; | ||
| 1074 | mb->command = ENABLE_CHDLC_COMMUNICATIONS; | ||
| 1075 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 1076 | if (err != COMMAND_OK) | ||
| 1077 | chdlc_error(card, err, mb); | ||
| 1078 | else | ||
| 1079 | card->u.c.comm_enabled=1; | ||
| 1080 | |||
| 1081 | return err; | ||
| 1082 | } | ||
| 1083 | |||
| 1084 | /*============================================================================ | ||
| 1085 | * Disable communications and Drop the Modem lines (DCD and RTS). | ||
| 1086 | */ | ||
| 1087 | static int chdlc_comm_disable (sdla_t* card) | ||
| 1088 | { | ||
| 1089 | int err; | ||
| 1090 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
| 1091 | |||
| 1092 | mb->buffer_length = 0; | ||
| 1093 | mb->command = DISABLE_CHDLC_COMMUNICATIONS; | ||
| 1094 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 1095 | if (err != COMMAND_OK) | ||
| 1096 | chdlc_error(card,err,mb); | ||
| 1097 | |||
| 1098 | return err; | ||
| 1099 | } | ||
| 1100 | |||
| 1101 | /*============================================================================ | ||
| 1102 | * Read communication error statistics. | ||
| 1103 | */ | ||
| 1104 | static int chdlc_read_comm_err_stats (sdla_t* card) | ||
| 1105 | { | ||
| 1106 | int err; | ||
| 1107 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
| 1108 | |||
| 1109 | mb->buffer_length = 0; | ||
| 1110 | mb->command = READ_COMMS_ERROR_STATS; | ||
| 1111 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 1112 | if (err != COMMAND_OK) | ||
| 1113 | chdlc_error(card,err,mb); | ||
| 1114 | return err; | ||
| 1115 | } | ||
| 1116 | |||
| 1117 | |||
| 1118 | /*============================================================================ | ||
| 1119 | * Read CHDLC operational statistics. | ||
| 1120 | */ | ||
| 1121 | static int chdlc_read_op_stats (sdla_t* card) | ||
| 1122 | { | ||
| 1123 | int err; | ||
| 1124 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
| 1125 | |||
| 1126 | mb->buffer_length = 0; | ||
| 1127 | mb->command = READ_CHDLC_OPERATIONAL_STATS; | ||
| 1128 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 1129 | if (err != COMMAND_OK) | ||
| 1130 | chdlc_error(card,err,mb); | ||
| 1131 | return err; | ||
| 1132 | } | ||
| 1133 | |||
| 1134 | |||
| 1135 | /*============================================================================ | ||
| 1136 | * Update communications error and general packet statistics. | ||
| 1137 | */ | ||
| 1138 | static int update_comms_stats(sdla_t* card, | ||
| 1139 | chdlc_private_area_t* chdlc_priv_area) | ||
| 1140 | { | ||
| 1141 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
| 1142 | COMMS_ERROR_STATS_STRUCT* err_stats; | ||
| 1143 | CHDLC_OPERATIONAL_STATS_STRUCT *op_stats; | ||
| 1144 | |||
| 1145 | /* on the first timer interrupt, read the comms error statistics */ | ||
| 1146 | if(chdlc_priv_area->update_comms_stats == 2) { | ||
| 1147 | if(chdlc_read_comm_err_stats(card)) | ||
| 1148 | return 1; | ||
| 1149 | err_stats = (COMMS_ERROR_STATS_STRUCT *)mb->data; | ||
| 1150 | card->wandev.stats.rx_over_errors = | ||
| 1151 | err_stats->Rx_overrun_err_count; | ||
| 1152 | card->wandev.stats.rx_crc_errors = | ||
| 1153 | err_stats->CRC_err_count; | ||
| 1154 | card->wandev.stats.rx_frame_errors = | ||
| 1155 | err_stats->Rx_abort_count; | ||
| 1156 | card->wandev.stats.rx_fifo_errors = | ||
| 1157 | err_stats->Rx_dis_pri_bfrs_full_count; | ||
| 1158 | card->wandev.stats.rx_missed_errors = | ||
| 1159 | card->wandev.stats.rx_fifo_errors; | ||
| 1160 | card->wandev.stats.tx_aborted_errors = | ||
| 1161 | err_stats->sec_Tx_abort_count; | ||
| 1162 | } | ||
| 1163 | |||
| 1164 | /* on the second timer interrupt, read the operational statistics */ | ||
| 1165 | else { | ||
| 1166 | if(chdlc_read_op_stats(card)) | ||
| 1167 | return 1; | ||
| 1168 | op_stats = (CHDLC_OPERATIONAL_STATS_STRUCT *)mb->data; | ||
| 1169 | card->wandev.stats.rx_length_errors = | ||
| 1170 | (op_stats->Rx_Data_discard_short_count + | ||
| 1171 | op_stats->Rx_Data_discard_long_count); | ||
| 1172 | } | ||
| 1173 | |||
| 1174 | return 0; | ||
| 1175 | } | ||
| 1176 | |||
| 1177 | /*============================================================================ | ||
| 1178 | * Send packet. | ||
| 1179 | * Return: 0 - o.k. | ||
| 1180 | * 1 - no transmit buffers available | ||
| 1181 | */ | ||
| 1182 | static int chdlc_send (sdla_t* card, void* data, unsigned len) | ||
| 1183 | { | ||
| 1184 | CHDLC_DATA_TX_STATUS_EL_STRUCT *txbuf = card->u.c.txbuf; | ||
| 1185 | |||
| 1186 | if (txbuf->opp_flag) | ||
| 1187 | return 1; | ||
| 1188 | |||
| 1189 | sdla_poke(&card->hw, txbuf->ptr_data_bfr, data, len); | ||
| 1190 | |||
| 1191 | txbuf->frame_length = len; | ||
| 1192 | txbuf->opp_flag = 1; /* start transmission */ | ||
| 1193 | |||
| 1194 | /* Update transmit buffer control fields */ | ||
| 1195 | card->u.c.txbuf = ++txbuf; | ||
| 1196 | |||
| 1197 | if ((void*)txbuf > card->u.c.txbuf_last) | ||
| 1198 | card->u.c.txbuf = card->u.c.txbuf_base; | ||
| 1199 | |||
| 1200 | return 0; | ||
| 1201 | } | ||
| 1202 | |||
| 1203 | /****** Firmware Error Handler **********************************************/ | ||
| 1204 | |||
| 1205 | /*============================================================================ | ||
| 1206 | * Firmware error handler. | ||
| 1207 | * This routine is called whenever firmware command returns non-zero | ||
| 1208 | * return code. | ||
| 1209 | * | ||
| 1210 | * Return zero if previous command has to be cancelled. | ||
| 1211 | */ | ||
| 1212 | static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb) | ||
| 1213 | { | ||
| 1214 | unsigned cmd = mb->command; | ||
| 1215 | |||
| 1216 | switch (err) { | ||
| 1217 | |||
| 1218 | case CMD_TIMEOUT: | ||
| 1219 | printk(KERN_ERR "%s: command 0x%02X timed out!\n", | ||
| 1220 | card->devname, cmd); | ||
| 1221 | break; | ||
| 1222 | |||
| 1223 | case S514_BOTH_PORTS_SAME_CLK_MODE: | ||
| 1224 | if(cmd == SET_CHDLC_CONFIGURATION) { | ||
| 1225 | printk(KERN_INFO | ||
| 1226 | "%s: Configure both ports for the same clock source\n", | ||
| 1227 | card->devname); | ||
| 1228 | break; | ||
| 1229 | } | ||
| 1230 | |||
| 1231 | default: | ||
| 1232 | printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", | ||
| 1233 | card->devname, cmd, err); | ||
| 1234 | } | ||
| 1235 | |||
| 1236 | return 0; | ||
| 1237 | } | ||
| 1238 | |||
| 1239 | /****** Interrupt Handlers **************************************************/ | ||
| 1240 | |||
| 1241 | /*============================================================================ | ||
| 1242 | * Cisco HDLC interrupt service routine. | ||
| 1243 | */ | ||
| 1244 | STATIC void wsppp_isr (sdla_t* card) | ||
| 1245 | { | ||
| 1246 | struct net_device* dev; | ||
| 1247 | SHARED_MEMORY_INFO_STRUCT* flags = NULL; | ||
| 1248 | int i; | ||
| 1249 | sdla_t *my_card; | ||
| 1250 | |||
| 1251 | |||
| 1252 | /* Check for which port the interrupt has been generated | ||
| 1253 | * Since Secondary Port is piggybacking on the Primary | ||
| 1254 | * the check must be done here. | ||
| 1255 | */ | ||
| 1256 | |||
| 1257 | flags = card->u.c.flags; | ||
| 1258 | if (!flags->interrupt_info_struct.interrupt_type){ | ||
| 1259 | /* Check for a second port (piggybacking) */ | ||
| 1260 | if((my_card = card->next)){ | ||
| 1261 | flags = my_card->u.c.flags; | ||
| 1262 | if (flags->interrupt_info_struct.interrupt_type){ | ||
| 1263 | card = my_card; | ||
| 1264 | card->isr(card); | ||
| 1265 | return; | ||
| 1266 | } | ||
| 1267 | } | ||
| 1268 | } | ||
| 1269 | |||
| 1270 | dev = card->wandev.dev; | ||
| 1271 | card->in_isr = 1; | ||
| 1272 | flags = card->u.c.flags; | ||
| 1273 | |||
| 1274 | /* If we get an interrupt with no network device, stop the interrupts | ||
| 1275 | * and issue an error */ | ||
| 1276 | if ((!dev || !dev->priv) && flags->interrupt_info_struct.interrupt_type != | ||
| 1277 | COMMAND_COMPLETE_APP_INT_PEND){ | ||
| 1278 | goto isr_done; | ||
| 1279 | } | ||
| 1280 | |||
| 1281 | |||
| 1282 | /* if critical due to peripheral operations | ||
| 1283 | * ie. update() or getstats() then reset the interrupt and | ||
| 1284 | * wait for the board to retrigger. | ||
| 1285 | */ | ||
| 1286 | if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { | ||
| 1287 | flags->interrupt_info_struct. | ||
| 1288 | interrupt_type = 0; | ||
| 1289 | goto isr_done; | ||
| 1290 | } | ||
| 1291 | |||
| 1292 | |||
| 1293 | /* On a 508 Card, if critical due to if_send | ||
| 1294 | * Major Error !!! | ||
| 1295 | */ | ||
| 1296 | if(card->hw.type != SDLA_S514) { | ||
| 1297 | if(test_bit(0, (void*)&card->wandev.critical)) { | ||
| 1298 | printk(KERN_INFO "%s: Critical while in ISR: %lx\n", | ||
| 1299 | card->devname, card->wandev.critical); | ||
| 1300 | goto isr_done; | ||
| 1301 | } | ||
| 1302 | } | ||
| 1303 | |||
| 1304 | switch(flags->interrupt_info_struct.interrupt_type) { | ||
| 1305 | |||
| 1306 | case RX_APP_INT_PEND: /* 0x01: receive interrupt */ | ||
| 1307 | rx_intr(card); | ||
| 1308 | break; | ||
| 1309 | |||
| 1310 | case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ | ||
| 1311 | flags->interrupt_info_struct.interrupt_permission &= | ||
| 1312 | ~APP_INT_ON_TX_FRAME; | ||
| 1313 | |||
| 1314 | netif_wake_queue(dev); | ||
| 1315 | break; | ||
| 1316 | |||
| 1317 | case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */ | ||
| 1318 | ++ Intr_test_counter; | ||
| 1319 | break; | ||
| 1320 | |||
| 1321 | case CHDLC_EXCEP_COND_APP_INT_PEND: /* 0x20 */ | ||
| 1322 | process_chdlc_exception(card); | ||
| 1323 | break; | ||
| 1324 | |||
| 1325 | case GLOBAL_EXCEP_COND_APP_INT_PEND: | ||
| 1326 | process_global_exception(card); | ||
| 1327 | break; | ||
| 1328 | |||
| 1329 | case TIMER_APP_INT_PEND: | ||
| 1330 | timer_intr(card); | ||
| 1331 | break; | ||
| 1332 | |||
| 1333 | default: | ||
| 1334 | printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", | ||
| 1335 | card->devname, | ||
| 1336 | flags->interrupt_info_struct.interrupt_type); | ||
| 1337 | printk(KERN_INFO "Code name: "); | ||
| 1338 | for(i = 0; i < 4; i ++) | ||
| 1339 | printk(KERN_INFO "%c", | ||
| 1340 | flags->global_info_struct.codename[i]); | ||
| 1341 | printk(KERN_INFO "\nCode version: "); | ||
| 1342 | for(i = 0; i < 4; i ++) | ||
| 1343 | printk(KERN_INFO "%c", | ||
| 1344 | flags->global_info_struct.codeversion[i]); | ||
| 1345 | printk(KERN_INFO "\n"); | ||
| 1346 | break; | ||
| 1347 | } | ||
| 1348 | |||
| 1349 | isr_done: | ||
| 1350 | card->in_isr = 0; | ||
| 1351 | flags->interrupt_info_struct.interrupt_type = 0; | ||
| 1352 | } | ||
| 1353 | |||
| 1354 | /*============================================================================ | ||
| 1355 | * Receive interrupt handler. | ||
| 1356 | */ | ||
| 1357 | static void rx_intr (sdla_t* card) | ||
| 1358 | { | ||
| 1359 | struct net_device *dev; | ||
| 1360 | chdlc_private_area_t *chdlc_priv_area; | ||
| 1361 | SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; | ||
| 1362 | CHDLC_DATA_RX_STATUS_EL_STRUCT *rxbuf = card->u.c.rxmb; | ||
| 1363 | struct sk_buff *skb; | ||
| 1364 | unsigned len; | ||
| 1365 | unsigned addr = rxbuf->ptr_data_bfr; | ||
| 1366 | void *buf; | ||
| 1367 | int i,udp_type; | ||
| 1368 | |||
| 1369 | if (rxbuf->opp_flag != 0x01) { | ||
| 1370 | printk(KERN_INFO | ||
| 1371 | "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", | ||
| 1372 | card->devname, (unsigned)rxbuf, rxbuf->opp_flag); | ||
| 1373 | printk(KERN_INFO "Code name: "); | ||
| 1374 | for(i = 0; i < 4; i ++) | ||
| 1375 | printk(KERN_INFO "%c", | ||
| 1376 | flags->global_info_struct.codename[i]); | ||
| 1377 | printk(KERN_INFO "\nCode version: "); | ||
| 1378 | for(i = 0; i < 4; i ++) | ||
| 1379 | printk(KERN_INFO "%c", | ||
| 1380 | flags->global_info_struct.codeversion[i]); | ||
| 1381 | printk(KERN_INFO "\n"); | ||
| 1382 | |||
| 1383 | |||
| 1384 | /* Bug Fix: Mar 6 2000 | ||
| 1385 | * If we get a corrupted mailbox, it measn that driver | ||
| 1386 | * is out of sync with the firmware. There is no recovery. | ||
| 1387 | * If we don't turn off all interrupts for this card | ||
| 1388 | * the machine will crash. | ||
| 1389 | */ | ||
| 1390 | printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); | ||
| 1391 | printk(KERN_INFO "Please contact Sangoma Technologies !\n"); | ||
| 1392 | chdlc_set_intr_mode(card,0); | ||
| 1393 | return; | ||
| 1394 | } | ||
| 1395 | |||
| 1396 | dev = card->wandev.dev; | ||
| 1397 | |||
| 1398 | if (!dev){ | ||
| 1399 | goto rx_exit; | ||
| 1400 | } | ||
| 1401 | |||
| 1402 | if (!netif_running(dev)){ | ||
| 1403 | goto rx_exit; | ||
| 1404 | } | ||
| 1405 | |||
| 1406 | chdlc_priv_area = dev->priv; | ||
| 1407 | |||
| 1408 | if (rxbuf->error_flag){ | ||
| 1409 | goto rx_exit; | ||
| 1410 | } | ||
| 1411 | /* Take off two CRC bytes */ | ||
| 1412 | |||
| 1413 | if (rxbuf->frame_length < 7 || rxbuf->frame_length > 1506 ){ | ||
| 1414 | goto rx_exit; | ||
| 1415 | } | ||
| 1416 | |||
| 1417 | len = rxbuf->frame_length - CRC_LENGTH; | ||
| 1418 | |||
| 1419 | /* Allocate socket buffer */ | ||
| 1420 | skb = dev_alloc_skb(len); | ||
| 1421 | |||
| 1422 | if (skb == NULL) { | ||
| 1423 | if (net_ratelimit()){ | ||
| 1424 | printk(KERN_INFO "%s: no socket buffers available!\n", | ||
| 1425 | card->devname); | ||
| 1426 | } | ||
| 1427 | ++card->wandev.stats.rx_dropped; | ||
| 1428 | goto rx_exit; | ||
| 1429 | } | ||
| 1430 | |||
| 1431 | /* Copy data to the socket buffer */ | ||
| 1432 | if((addr + len) > card->u.c.rx_top + 1) { | ||
| 1433 | unsigned tmp = card->u.c.rx_top - addr + 1; | ||
| 1434 | buf = skb_put(skb, tmp); | ||
| 1435 | sdla_peek(&card->hw, addr, buf, tmp); | ||
| 1436 | addr = card->u.c.rx_base; | ||
| 1437 | len -= tmp; | ||
| 1438 | } | ||
| 1439 | |||
| 1440 | buf = skb_put(skb, len); | ||
| 1441 | sdla_peek(&card->hw, addr, buf, len); | ||
| 1442 | |||
| 1443 | skb->protocol = htons(ETH_P_WAN_PPP); | ||
| 1444 | |||
| 1445 | card->wandev.stats.rx_packets ++; | ||
| 1446 | card->wandev.stats.rx_bytes += skb->len; | ||
| 1447 | udp_type = udp_pkt_type( skb, card ); | ||
| 1448 | |||
| 1449 | if(udp_type == UDP_CPIPE_TYPE) { | ||
| 1450 | if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, | ||
| 1451 | card, skb, dev, chdlc_priv_area)) { | ||
| 1452 | flags->interrupt_info_struct. | ||
| 1453 | interrupt_permission |= | ||
| 1454 | APP_INT_ON_TIMER; | ||
| 1455 | } | ||
| 1456 | }else{ | ||
| 1457 | /* Pass it up the protocol stack */ | ||
| 1458 | skb->dev = dev; | ||
| 1459 | skb->mac.raw = skb->data; | ||
| 1460 | netif_rx(skb); | ||
| 1461 | dev->last_rx = jiffies; | ||
| 1462 | } | ||
| 1463 | |||
| 1464 | rx_exit: | ||
| 1465 | /* Release buffer element and calculate a pointer to the next one */ | ||
| 1466 | rxbuf->opp_flag = 0x00; | ||
| 1467 | card->u.c.rxmb = ++ rxbuf; | ||
| 1468 | if((void*)rxbuf > card->u.c.rxbuf_last){ | ||
| 1469 | card->u.c.rxmb = card->u.c.rxbuf_base; | ||
| 1470 | } | ||
| 1471 | } | ||
| 1472 | |||
| 1473 | /*============================================================================ | ||
| 1474 | * Timer interrupt handler. | ||
| 1475 | * The timer interrupt is used for two purposes: | ||
| 1476 | * 1) Processing udp calls from 'cpipemon'. | ||
| 1477 | * 2) Reading board-level statistics for updating the proc file system. | ||
| 1478 | */ | ||
| 1479 | void timer_intr(sdla_t *card) | ||
| 1480 | { | ||
| 1481 | struct net_device* dev; | ||
| 1482 | chdlc_private_area_t* chdlc_priv_area = NULL; | ||
| 1483 | SHARED_MEMORY_INFO_STRUCT* flags = NULL; | ||
| 1484 | |||
| 1485 | dev = card->wandev.dev; | ||
| 1486 | chdlc_priv_area = dev->priv; | ||
| 1487 | |||
| 1488 | if (chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG) { | ||
| 1489 | if (!config_chdlc(card)){ | ||
| 1490 | chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG; | ||
| 1491 | } | ||
| 1492 | } | ||
| 1493 | |||
| 1494 | /* process a udp call if pending */ | ||
| 1495 | if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP) { | ||
| 1496 | process_udp_mgmt_pkt(card, dev, | ||
| 1497 | chdlc_priv_area); | ||
| 1498 | chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP; | ||
| 1499 | } | ||
| 1500 | |||
| 1501 | |||
| 1502 | /* read the communications statistics if required */ | ||
| 1503 | if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE) { | ||
| 1504 | update_comms_stats(card, chdlc_priv_area); | ||
| 1505 | if(!(-- chdlc_priv_area->update_comms_stats)) { | ||
| 1506 | chdlc_priv_area->timer_int_enabled &= | ||
| 1507 | ~TMR_INT_ENABLED_UPDATE; | ||
| 1508 | } | ||
| 1509 | } | ||
| 1510 | |||
| 1511 | /* only disable the timer interrupt if there are no udp or statistic */ | ||
| 1512 | /* updates pending */ | ||
| 1513 | if(!chdlc_priv_area->timer_int_enabled) { | ||
| 1514 | flags = card->u.c.flags; | ||
| 1515 | flags->interrupt_info_struct.interrupt_permission &= | ||
| 1516 | ~APP_INT_ON_TIMER; | ||
| 1517 | } | ||
| 1518 | } | ||
| 1519 | |||
| 1520 | /*------------------------------------------------------------------------------ | ||
| 1521 | Miscellaneous Functions | ||
| 1522 | - set_chdlc_config() used to set configuration options on the board | ||
| 1523 | ------------------------------------------------------------------------------*/ | ||
| 1524 | |||
| 1525 | static int set_chdlc_config(sdla_t* card) | ||
| 1526 | { | ||
| 1527 | |||
| 1528 | CHDLC_CONFIGURATION_STRUCT cfg; | ||
| 1529 | |||
| 1530 | memset(&cfg, 0, sizeof(CHDLC_CONFIGURATION_STRUCT)); | ||
| 1531 | |||
| 1532 | if(card->wandev.clocking) | ||
| 1533 | cfg.baud_rate = card->wandev.bps; | ||
| 1534 | |||
| 1535 | cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? | ||
| 1536 | INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; | ||
| 1537 | |||
| 1538 | cfg.modem_config_options = 0; | ||
| 1539 | //API OPTIONS | ||
| 1540 | cfg.CHDLC_API_options = DISCARD_RX_ERROR_FRAMES; | ||
| 1541 | cfg.modem_status_timer = 100; | ||
| 1542 | cfg.CHDLC_protocol_options = HDLC_STREAMING_MODE; | ||
| 1543 | cfg.percent_data_buffer_for_Tx = 50; | ||
| 1544 | cfg.CHDLC_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | | ||
| 1545 | CHDLC_RX_DATA_BYTE_COUNT_STAT); | ||
| 1546 | cfg.max_CHDLC_data_field_length = card->wandev.mtu; | ||
| 1547 | |||
| 1548 | cfg.transmit_keepalive_timer = 0; | ||
| 1549 | cfg.receive_keepalive_timer = 0; | ||
| 1550 | cfg.keepalive_error_tolerance = 0; | ||
| 1551 | cfg.SLARP_request_timer = 0; | ||
| 1552 | |||
| 1553 | cfg.IP_address = 0; | ||
| 1554 | cfg.IP_netmask = 0; | ||
| 1555 | |||
| 1556 | return chdlc_configure(card, &cfg); | ||
| 1557 | } | ||
| 1558 | |||
| 1559 | /*============================================================================ | ||
| 1560 | * Process global exception condition | ||
| 1561 | */ | ||
| 1562 | static int process_global_exception(sdla_t *card) | ||
| 1563 | { | ||
| 1564 | CHDLC_MAILBOX_STRUCT* mbox = card->mbox; | ||
| 1565 | int err; | ||
| 1566 | |||
| 1567 | mbox->buffer_length = 0; | ||
| 1568 | mbox->command = READ_GLOBAL_EXCEPTION_CONDITION; | ||
| 1569 | err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; | ||
| 1570 | |||
| 1571 | if(err != CMD_TIMEOUT ){ | ||
| 1572 | |||
| 1573 | switch(mbox->return_code) { | ||
| 1574 | |||
| 1575 | case EXCEP_MODEM_STATUS_CHANGE: | ||
| 1576 | |||
| 1577 | printk(KERN_INFO "%s: Modem status change\n", | ||
| 1578 | card->devname); | ||
| 1579 | |||
| 1580 | switch(mbox->data[0] & (DCD_HIGH | CTS_HIGH)) { | ||
| 1581 | case (DCD_HIGH): | ||
| 1582 | printk(KERN_INFO "%s: DCD high, CTS low\n",card->devname); | ||
| 1583 | break; | ||
| 1584 | case (CTS_HIGH): | ||
| 1585 | printk(KERN_INFO "%s: DCD low, CTS high\n",card->devname); | ||
| 1586 | break; | ||
| 1587 | case ((DCD_HIGH | CTS_HIGH)): | ||
| 1588 | printk(KERN_INFO "%s: DCD high, CTS high\n",card->devname); | ||
| 1589 | break; | ||
| 1590 | default: | ||
| 1591 | printk(KERN_INFO "%s: DCD low, CTS low\n",card->devname); | ||
| 1592 | break; | ||
| 1593 | } | ||
| 1594 | |||
| 1595 | if (!(mbox->data[0] & DCD_HIGH) || !(mbox->data[0] & DCD_HIGH)){ | ||
| 1596 | //printk(KERN_INFO "Sending TERM Request Manually !\n"); | ||
| 1597 | send_ppp_term_request(card->wandev.dev); | ||
| 1598 | } | ||
| 1599 | break; | ||
| 1600 | |||
| 1601 | case EXCEP_TRC_DISABLED: | ||
| 1602 | printk(KERN_INFO "%s: Line trace disabled\n", | ||
| 1603 | card->devname); | ||
| 1604 | break; | ||
| 1605 | |||
| 1606 | case EXCEP_IRQ_TIMEOUT: | ||
| 1607 | printk(KERN_INFO "%s: IRQ timeout occurred\n", | ||
| 1608 | card->devname); | ||
| 1609 | break; | ||
| 1610 | |||
| 1611 | default: | ||
| 1612 | printk(KERN_INFO "%s: Global exception %x\n", | ||
| 1613 | card->devname, mbox->return_code); | ||
| 1614 | break; | ||
| 1615 | } | ||
| 1616 | } | ||
| 1617 | return 0; | ||
| 1618 | } | ||
| 1619 | |||
| 1620 | |||
| 1621 | /*============================================================================ | ||
| 1622 | * Process chdlc exception condition | ||
| 1623 | */ | ||
| 1624 | static int process_chdlc_exception(sdla_t *card) | ||
| 1625 | { | ||
| 1626 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
| 1627 | int err; | ||
| 1628 | |||
| 1629 | mb->buffer_length = 0; | ||
| 1630 | mb->command = READ_CHDLC_EXCEPTION_CONDITION; | ||
| 1631 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 1632 | if(err != CMD_TIMEOUT) { | ||
| 1633 | |||
| 1634 | switch (err) { | ||
| 1635 | |||
| 1636 | case EXCEP_LINK_ACTIVE: | ||
| 1637 | port_set_state(card, WAN_CONNECTED); | ||
| 1638 | break; | ||
| 1639 | |||
| 1640 | case EXCEP_LINK_INACTIVE_MODEM: | ||
| 1641 | port_set_state(card, WAN_DISCONNECTED); | ||
| 1642 | break; | ||
| 1643 | |||
| 1644 | case EXCEP_LOOPBACK_CONDITION: | ||
| 1645 | printk(KERN_INFO "%s: Loopback Condition Detected.\n", | ||
| 1646 | card->devname); | ||
| 1647 | break; | ||
| 1648 | |||
| 1649 | case NO_CHDLC_EXCEP_COND_TO_REPORT: | ||
| 1650 | printk(KERN_INFO "%s: No exceptions reported.\n", | ||
| 1651 | card->devname); | ||
| 1652 | break; | ||
| 1653 | default: | ||
| 1654 | printk(KERN_INFO "%s: Exception Condition %x!\n", | ||
| 1655 | card->devname,err); | ||
| 1656 | break; | ||
| 1657 | } | ||
| 1658 | |||
| 1659 | } | ||
| 1660 | return 0; | ||
| 1661 | } | ||
| 1662 | |||
| 1663 | |||
| 1664 | /*============================================================================= | ||
| 1665 | * Store a UDP management packet for later processing. | ||
| 1666 | */ | ||
| 1667 | |||
| 1668 | static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, | ||
| 1669 | struct sk_buff *skb, struct net_device* dev, | ||
| 1670 | chdlc_private_area_t* chdlc_priv_area ) | ||
| 1671 | { | ||
| 1672 | int udp_pkt_stored = 0; | ||
| 1673 | |||
| 1674 | if(!chdlc_priv_area->udp_pkt_lgth && | ||
| 1675 | (skb->len <= MAX_LGTH_UDP_MGNT_PKT)) { | ||
| 1676 | chdlc_priv_area->udp_pkt_lgth = skb->len; | ||
| 1677 | chdlc_priv_area->udp_pkt_src = udp_pkt_src; | ||
| 1678 | memcpy(chdlc_priv_area->udp_pkt_data, skb->data, skb->len); | ||
| 1679 | chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UDP; | ||
| 1680 | udp_pkt_stored = 1; | ||
| 1681 | } | ||
| 1682 | |||
| 1683 | if(udp_pkt_src == UDP_PKT_FRM_STACK) | ||
| 1684 | dev_kfree_skb_any(skb); | ||
| 1685 | else | ||
| 1686 | dev_kfree_skb_any(skb); | ||
| 1687 | |||
| 1688 | return(udp_pkt_stored); | ||
| 1689 | } | ||
| 1690 | |||
| 1691 | |||
| 1692 | /*============================================================================= | ||
| 1693 | * Process UDP management packet. | ||
| 1694 | */ | ||
| 1695 | |||
| 1696 | static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, | ||
| 1697 | chdlc_private_area_t* chdlc_priv_area ) | ||
| 1698 | { | ||
| 1699 | unsigned char *buf; | ||
| 1700 | unsigned int frames, len; | ||
| 1701 | struct sk_buff *new_skb; | ||
| 1702 | unsigned short buffer_length, real_len; | ||
| 1703 | unsigned long data_ptr; | ||
| 1704 | unsigned data_length; | ||
| 1705 | int udp_mgmt_req_valid = 1; | ||
| 1706 | CHDLC_MAILBOX_STRUCT *mb = card->mbox; | ||
| 1707 | SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; | ||
| 1708 | chdlc_udp_pkt_t *chdlc_udp_pkt; | ||
| 1709 | struct timeval tv; | ||
| 1710 | int err; | ||
| 1711 | char ut_char; | ||
| 1712 | |||
| 1713 | chdlc_udp_pkt = (chdlc_udp_pkt_t *) chdlc_priv_area->udp_pkt_data; | ||
| 1714 | |||
| 1715 | if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { | ||
| 1716 | |||
| 1717 | switch(chdlc_udp_pkt->cblock.command) { | ||
| 1718 | case READ_GLOBAL_STATISTICS: | ||
| 1719 | case READ_MODEM_STATUS: | ||
| 1720 | case READ_CHDLC_LINK_STATUS: | ||
| 1721 | case CPIPE_ROUTER_UP_TIME: | ||
| 1722 | case READ_COMMS_ERROR_STATS: | ||
| 1723 | case READ_CHDLC_OPERATIONAL_STATS: | ||
| 1724 | |||
| 1725 | /* These two commands are executed for | ||
| 1726 | * each request */ | ||
| 1727 | case READ_CHDLC_CONFIGURATION: | ||
| 1728 | case READ_CHDLC_CODE_VERSION: | ||
| 1729 | udp_mgmt_req_valid = 1; | ||
| 1730 | break; | ||
| 1731 | default: | ||
| 1732 | udp_mgmt_req_valid = 0; | ||
| 1733 | break; | ||
| 1734 | } | ||
| 1735 | } | ||
| 1736 | |||
| 1737 | if(!udp_mgmt_req_valid) { | ||
| 1738 | |||
| 1739 | /* set length to 0 */ | ||
| 1740 | chdlc_udp_pkt->cblock.buffer_length = 0; | ||
| 1741 | |||
| 1742 | /* set return code */ | ||
| 1743 | chdlc_udp_pkt->cblock.return_code = 0xCD; | ||
| 1744 | |||
| 1745 | if (net_ratelimit()){ | ||
| 1746 | printk(KERN_INFO | ||
| 1747 | "%s: Warning, Illegal UDP command attempted from network: %x\n", | ||
| 1748 | card->devname,chdlc_udp_pkt->cblock.command); | ||
| 1749 | } | ||
| 1750 | |||
| 1751 | } else { | ||
| 1752 | unsigned long trace_status_cfg_addr = 0; | ||
| 1753 | TRACE_STATUS_EL_CFG_STRUCT trace_cfg_struct; | ||
| 1754 | TRACE_STATUS_ELEMENT_STRUCT trace_element_struct; | ||
| 1755 | |||
| 1756 | switch(chdlc_udp_pkt->cblock.command) { | ||
| 1757 | |||
| 1758 | case CPIPE_ENABLE_TRACING: | ||
| 1759 | if (!chdlc_priv_area->TracingEnabled) { | ||
| 1760 | |||
| 1761 | /* OPERATE_DATALINE_MONITOR */ | ||
| 1762 | |||
| 1763 | mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); | ||
| 1764 | mb->command = SET_TRACE_CONFIGURATION; | ||
| 1765 | |||
| 1766 | ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> | ||
| 1767 | trace_config = TRACE_ACTIVE; | ||
| 1768 | /* Trace delay mode is not used because it slows | ||
| 1769 | down transfer and results in a standoff situation | ||
| 1770 | when there is a lot of data */ | ||
| 1771 | |||
| 1772 | /* Configure the Trace based on user inputs */ | ||
| 1773 | ((LINE_TRACE_CONFIG_STRUCT *)mb->data)->trace_config |= | ||
| 1774 | chdlc_udp_pkt->data[0]; | ||
| 1775 | |||
| 1776 | ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> | ||
| 1777 | trace_deactivation_timer = 4000; | ||
| 1778 | |||
| 1779 | |||
| 1780 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 1781 | if (err != COMMAND_OK) { | ||
| 1782 | chdlc_error(card,err,mb); | ||
| 1783 | card->TracingEnabled = 0; | ||
| 1784 | chdlc_udp_pkt->cblock.return_code = err; | ||
| 1785 | mb->buffer_length = 0; | ||
| 1786 | break; | ||
| 1787 | } | ||
| 1788 | |||
| 1789 | /* Get the base address of the trace element list */ | ||
| 1790 | mb->buffer_length = 0; | ||
| 1791 | mb->command = READ_TRACE_CONFIGURATION; | ||
| 1792 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 1793 | |||
| 1794 | if (err != COMMAND_OK) { | ||
| 1795 | chdlc_error(card,err,mb); | ||
| 1796 | chdlc_priv_area->TracingEnabled = 0; | ||
| 1797 | chdlc_udp_pkt->cblock.return_code = err; | ||
| 1798 | mb->buffer_length = 0; | ||
| 1799 | break; | ||
| 1800 | } | ||
| 1801 | |||
| 1802 | trace_status_cfg_addr =((LINE_TRACE_CONFIG_STRUCT *) | ||
| 1803 | mb->data) -> ptr_trace_stat_el_cfg_struct; | ||
| 1804 | |||
| 1805 | sdla_peek(&card->hw, trace_status_cfg_addr, | ||
| 1806 | &trace_cfg_struct, sizeof(trace_cfg_struct)); | ||
| 1807 | |||
| 1808 | chdlc_priv_area->start_trace_addr = trace_cfg_struct. | ||
| 1809 | base_addr_trace_status_elements; | ||
| 1810 | |||
| 1811 | chdlc_priv_area->number_trace_elements = | ||
| 1812 | trace_cfg_struct.number_trace_status_elements; | ||
| 1813 | |||
| 1814 | chdlc_priv_area->end_trace_addr = (unsigned long) | ||
| 1815 | ((TRACE_STATUS_ELEMENT_STRUCT *) | ||
| 1816 | chdlc_priv_area->start_trace_addr + | ||
| 1817 | (chdlc_priv_area->number_trace_elements - 1)); | ||
| 1818 | |||
| 1819 | chdlc_priv_area->base_addr_trace_buffer = | ||
| 1820 | trace_cfg_struct.base_addr_trace_buffer; | ||
| 1821 | |||
| 1822 | chdlc_priv_area->end_addr_trace_buffer = | ||
| 1823 | trace_cfg_struct.end_addr_trace_buffer; | ||
| 1824 | |||
| 1825 | chdlc_priv_area->curr_trace_addr = | ||
| 1826 | trace_cfg_struct.next_trace_element_to_use; | ||
| 1827 | |||
| 1828 | chdlc_priv_area->available_buffer_space = 2000 - | ||
| 1829 | sizeof(ip_pkt_t) - | ||
| 1830 | sizeof(udp_pkt_t) - | ||
| 1831 | sizeof(wp_mgmt_t) - | ||
| 1832 | sizeof(cblock_t) - | ||
| 1833 | sizeof(trace_info_t); | ||
| 1834 | } | ||
| 1835 | chdlc_udp_pkt->cblock.return_code = COMMAND_OK; | ||
| 1836 | mb->buffer_length = 0; | ||
| 1837 | chdlc_priv_area->TracingEnabled = 1; | ||
| 1838 | break; | ||
| 1839 | |||
| 1840 | |||
| 1841 | case CPIPE_DISABLE_TRACING: | ||
| 1842 | if (chdlc_priv_area->TracingEnabled) { | ||
| 1843 | |||
| 1844 | /* OPERATE_DATALINE_MONITOR */ | ||
| 1845 | mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); | ||
| 1846 | mb->command = SET_TRACE_CONFIGURATION; | ||
| 1847 | ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> | ||
| 1848 | trace_config = TRACE_INACTIVE; | ||
| 1849 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 1850 | } | ||
| 1851 | |||
| 1852 | chdlc_priv_area->TracingEnabled = 0; | ||
| 1853 | chdlc_udp_pkt->cblock.return_code = COMMAND_OK; | ||
| 1854 | mb->buffer_length = 0; | ||
| 1855 | break; | ||
| 1856 | |||
| 1857 | |||
| 1858 | case CPIPE_GET_TRACE_INFO: | ||
| 1859 | |||
| 1860 | if (!chdlc_priv_area->TracingEnabled) { | ||
| 1861 | chdlc_udp_pkt->cblock.return_code = 1; | ||
| 1862 | mb->buffer_length = 0; | ||
| 1863 | break; | ||
| 1864 | } | ||
| 1865 | |||
| 1866 | chdlc_udp_pkt->trace_info.ismoredata = 0x00; | ||
| 1867 | buffer_length = 0; /* offset of packet already occupied */ | ||
| 1868 | |||
| 1869 | for (frames=0; frames < chdlc_priv_area->number_trace_elements; frames++){ | ||
| 1870 | |||
| 1871 | trace_pkt_t *trace_pkt = (trace_pkt_t *) | ||
| 1872 | &chdlc_udp_pkt->data[buffer_length]; | ||
| 1873 | |||
| 1874 | sdla_peek(&card->hw, chdlc_priv_area->curr_trace_addr, | ||
| 1875 | (unsigned char *)&trace_element_struct, | ||
| 1876 | sizeof(TRACE_STATUS_ELEMENT_STRUCT)); | ||
| 1877 | |||
| 1878 | if (trace_element_struct.opp_flag == 0x00) { | ||
| 1879 | break; | ||
| 1880 | } | ||
| 1881 | |||
| 1882 | /* get pointer to real data */ | ||
| 1883 | data_ptr = trace_element_struct.ptr_data_bfr; | ||
| 1884 | |||
| 1885 | /* See if there is actual data on the trace buffer */ | ||
| 1886 | if (data_ptr){ | ||
| 1887 | data_length = trace_element_struct.trace_length; | ||
| 1888 | }else{ | ||
| 1889 | data_length = 0; | ||
| 1890 | chdlc_udp_pkt->trace_info.ismoredata = 0x01; | ||
| 1891 | } | ||
| 1892 | |||
| 1893 | if( (chdlc_priv_area->available_buffer_space - buffer_length) | ||
| 1894 | < ( sizeof(trace_pkt_t) + data_length) ) { | ||
| 1895 | |||
| 1896 | /* indicate there are more frames on board & exit */ | ||
| 1897 | chdlc_udp_pkt->trace_info.ismoredata = 0x01; | ||
| 1898 | break; | ||
| 1899 | } | ||
| 1900 | |||
| 1901 | trace_pkt->status = trace_element_struct.trace_type; | ||
| 1902 | |||
| 1903 | trace_pkt->time_stamp = | ||
| 1904 | trace_element_struct.trace_time_stamp; | ||
| 1905 | |||
| 1906 | trace_pkt->real_length = | ||
| 1907 | trace_element_struct.trace_length; | ||
| 1908 | |||
| 1909 | /* see if we can fit the frame into the user buffer */ | ||
| 1910 | real_len = trace_pkt->real_length; | ||
| 1911 | |||
| 1912 | if (data_ptr == 0) { | ||
| 1913 | trace_pkt->data_avail = 0x00; | ||
| 1914 | } else { | ||
| 1915 | unsigned tmp = 0; | ||
| 1916 | |||
| 1917 | /* get the data from circular buffer | ||
| 1918 | must check for end of buffer */ | ||
| 1919 | trace_pkt->data_avail = 0x01; | ||
| 1920 | |||
| 1921 | if ((data_ptr + real_len) > | ||
| 1922 | chdlc_priv_area->end_addr_trace_buffer + 1){ | ||
| 1923 | |||
| 1924 | tmp = chdlc_priv_area->end_addr_trace_buffer - data_ptr + 1; | ||
| 1925 | sdla_peek(&card->hw, data_ptr, | ||
| 1926 | trace_pkt->data,tmp); | ||
| 1927 | data_ptr = chdlc_priv_area->base_addr_trace_buffer; | ||
| 1928 | } | ||
| 1929 | |||
| 1930 | sdla_peek(&card->hw, data_ptr, | ||
| 1931 | &trace_pkt->data[tmp], real_len - tmp); | ||
| 1932 | } | ||
| 1933 | |||
| 1934 | /* zero the opp flag to show we got the frame */ | ||
| 1935 | ut_char = 0x00; | ||
| 1936 | sdla_poke(&card->hw, chdlc_priv_area->curr_trace_addr, &ut_char, 1); | ||
| 1937 | |||
| 1938 | /* now move onto the next frame */ | ||
| 1939 | chdlc_priv_area->curr_trace_addr += sizeof(TRACE_STATUS_ELEMENT_STRUCT); | ||
| 1940 | |||
| 1941 | /* check if we went over the last address */ | ||
| 1942 | if ( chdlc_priv_area->curr_trace_addr > chdlc_priv_area->end_trace_addr ) { | ||
| 1943 | chdlc_priv_area->curr_trace_addr = chdlc_priv_area->start_trace_addr; | ||
| 1944 | } | ||
| 1945 | |||
| 1946 | if(trace_pkt->data_avail == 0x01) { | ||
| 1947 | buffer_length += real_len - 1; | ||
| 1948 | } | ||
| 1949 | |||
| 1950 | /* for the header */ | ||
| 1951 | buffer_length += sizeof(trace_pkt_t); | ||
| 1952 | |||
| 1953 | } /* For Loop */ | ||
| 1954 | |||
| 1955 | if (frames == chdlc_priv_area->number_trace_elements){ | ||
| 1956 | chdlc_udp_pkt->trace_info.ismoredata = 0x01; | ||
| 1957 | } | ||
| 1958 | chdlc_udp_pkt->trace_info.num_frames = frames; | ||
| 1959 | |||
| 1960 | mb->buffer_length = buffer_length; | ||
| 1961 | chdlc_udp_pkt->cblock.buffer_length = buffer_length; | ||
| 1962 | |||
| 1963 | chdlc_udp_pkt->cblock.return_code = COMMAND_OK; | ||
| 1964 | |||
| 1965 | break; | ||
| 1966 | |||
| 1967 | |||
| 1968 | case CPIPE_FT1_READ_STATUS: | ||
| 1969 | ((unsigned char *)chdlc_udp_pkt->data )[0] = | ||
| 1970 | flags->FT1_info_struct.parallel_port_A_input; | ||
| 1971 | |||
| 1972 | ((unsigned char *)chdlc_udp_pkt->data )[1] = | ||
| 1973 | flags->FT1_info_struct.parallel_port_B_input; | ||
| 1974 | |||
| 1975 | chdlc_udp_pkt->cblock.return_code = COMMAND_OK; | ||
| 1976 | mb->buffer_length = 2; | ||
| 1977 | break; | ||
| 1978 | |||
| 1979 | case CPIPE_ROUTER_UP_TIME: | ||
| 1980 | do_gettimeofday( &tv ); | ||
| 1981 | chdlc_priv_area->router_up_time = tv.tv_sec - | ||
| 1982 | chdlc_priv_area->router_start_time; | ||
| 1983 | *(unsigned long *)&chdlc_udp_pkt->data = | ||
| 1984 | chdlc_priv_area->router_up_time; | ||
| 1985 | mb->buffer_length = sizeof(unsigned long); | ||
| 1986 | break; | ||
| 1987 | |||
| 1988 | case FT1_MONITOR_STATUS_CTRL: | ||
| 1989 | /* Enable FT1 MONITOR STATUS */ | ||
| 1990 | if ((chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_STATUS) || | ||
| 1991 | (chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_OP_STATS)) { | ||
| 1992 | |||
| 1993 | if( rCount++ != 0 ) { | ||
| 1994 | chdlc_udp_pkt->cblock. | ||
| 1995 | return_code = COMMAND_OK; | ||
| 1996 | mb->buffer_length = 1; | ||
| 1997 | break; | ||
| 1998 | } | ||
| 1999 | } | ||
| 2000 | |||
| 2001 | /* Disable FT1 MONITOR STATUS */ | ||
| 2002 | if( chdlc_udp_pkt->data[0] == 0) { | ||
| 2003 | |||
| 2004 | if( --rCount != 0) { | ||
| 2005 | chdlc_udp_pkt->cblock. | ||
| 2006 | return_code = COMMAND_OK; | ||
| 2007 | mb->buffer_length = 1; | ||
| 2008 | break; | ||
| 2009 | } | ||
| 2010 | } | ||
| 2011 | |||
| 2012 | default: | ||
| 2013 | /* it's a board command */ | ||
| 2014 | mb->command = chdlc_udp_pkt->cblock.command; | ||
| 2015 | mb->buffer_length = chdlc_udp_pkt->cblock.buffer_length; | ||
| 2016 | if (mb->buffer_length) { | ||
| 2017 | memcpy(&mb->data, (unsigned char *) chdlc_udp_pkt-> | ||
| 2018 | data, mb->buffer_length); | ||
| 2019 | } | ||
| 2020 | /* run the command on the board */ | ||
| 2021 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 2022 | if (err != COMMAND_OK) { | ||
| 2023 | break; | ||
| 2024 | } | ||
| 2025 | |||
| 2026 | /* copy the result back to our buffer */ | ||
| 2027 | memcpy(&chdlc_udp_pkt->cblock, mb, sizeof(cblock_t)); | ||
| 2028 | |||
| 2029 | if (mb->buffer_length) { | ||
| 2030 | memcpy(&chdlc_udp_pkt->data, &mb->data, | ||
| 2031 | mb->buffer_length); | ||
| 2032 | } | ||
| 2033 | |||
| 2034 | } /* end of switch */ | ||
| 2035 | } /* end of else */ | ||
| 2036 | |||
| 2037 | /* Fill UDP TTL */ | ||
| 2038 | chdlc_udp_pkt->ip_pkt.ttl = card->wandev.ttl; | ||
| 2039 | |||
| 2040 | len = reply_udp(chdlc_priv_area->udp_pkt_data, mb->buffer_length); | ||
| 2041 | |||
| 2042 | if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { | ||
| 2043 | if(!chdlc_send(card, chdlc_priv_area->udp_pkt_data, len)) { | ||
| 2044 | ++ card->wandev.stats.tx_packets; | ||
| 2045 | card->wandev.stats.tx_bytes += len; | ||
| 2046 | } | ||
| 2047 | } else { | ||
| 2048 | |||
| 2049 | /* Pass it up the stack | ||
| 2050 | Allocate socket buffer */ | ||
| 2051 | if ((new_skb = dev_alloc_skb(len)) != NULL) { | ||
| 2052 | /* copy data into new_skb */ | ||
| 2053 | |||
| 2054 | buf = skb_put(new_skb, len); | ||
| 2055 | memcpy(buf, chdlc_priv_area->udp_pkt_data, len); | ||
| 2056 | |||
| 2057 | /* Decapsulate pkt and pass it up the protocol stack */ | ||
| 2058 | new_skb->protocol = htons(ETH_P_IP); | ||
| 2059 | new_skb->dev = dev; | ||
| 2060 | new_skb->mac.raw = new_skb->data; | ||
| 2061 | |||
| 2062 | netif_rx(new_skb); | ||
| 2063 | dev->last_rx = jiffies; | ||
| 2064 | } else { | ||
| 2065 | |||
| 2066 | printk(KERN_INFO "%s: no socket buffers available!\n", | ||
| 2067 | card->devname); | ||
| 2068 | } | ||
| 2069 | } | ||
| 2070 | |||
| 2071 | chdlc_priv_area->udp_pkt_lgth = 0; | ||
| 2072 | |||
| 2073 | return 0; | ||
| 2074 | } | ||
| 2075 | |||
| 2076 | /*============================================================================ | ||
| 2077 | * Initialize Receive and Transmit Buffers. | ||
| 2078 | */ | ||
| 2079 | |||
| 2080 | static void init_chdlc_tx_rx_buff(sdla_t* card, struct net_device *dev) | ||
| 2081 | { | ||
| 2082 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
| 2083 | CHDLC_TX_STATUS_EL_CFG_STRUCT *tx_config; | ||
| 2084 | CHDLC_RX_STATUS_EL_CFG_STRUCT *rx_config; | ||
| 2085 | char err; | ||
| 2086 | |||
| 2087 | mb->buffer_length = 0; | ||
| 2088 | mb->command = READ_CHDLC_CONFIGURATION; | ||
| 2089 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 2090 | |||
| 2091 | if(err != COMMAND_OK) { | ||
| 2092 | chdlc_error(card,err,mb); | ||
| 2093 | return; | ||
| 2094 | } | ||
| 2095 | |||
| 2096 | if(card->hw.type == SDLA_S514) { | ||
| 2097 | tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + | ||
| 2098 | (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> | ||
| 2099 | ptr_CHDLC_Tx_stat_el_cfg_struct)); | ||
| 2100 | rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + | ||
| 2101 | (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> | ||
| 2102 | ptr_CHDLC_Rx_stat_el_cfg_struct)); | ||
| 2103 | |||
| 2104 | /* Setup Head and Tails for buffers */ | ||
| 2105 | card->u.c.txbuf_base = (void *)(card->hw.dpmbase + | ||
| 2106 | tx_config->base_addr_Tx_status_elements); | ||
| 2107 | card->u.c.txbuf_last = | ||
| 2108 | (CHDLC_DATA_TX_STATUS_EL_STRUCT *) | ||
| 2109 | card->u.c.txbuf_base + | ||
| 2110 | (tx_config->number_Tx_status_elements - 1); | ||
| 2111 | |||
| 2112 | card->u.c.rxbuf_base = (void *)(card->hw.dpmbase + | ||
| 2113 | rx_config->base_addr_Rx_status_elements); | ||
| 2114 | card->u.c.rxbuf_last = | ||
| 2115 | (CHDLC_DATA_RX_STATUS_EL_STRUCT *) | ||
| 2116 | card->u.c.rxbuf_base + | ||
| 2117 | (rx_config->number_Rx_status_elements - 1); | ||
| 2118 | |||
| 2119 | /* Set up next pointer to be used */ | ||
| 2120 | card->u.c.txbuf = (void *)(card->hw.dpmbase + | ||
| 2121 | tx_config->next_Tx_status_element_to_use); | ||
| 2122 | card->u.c.rxmb = (void *)(card->hw.dpmbase + | ||
| 2123 | rx_config->next_Rx_status_element_to_use); | ||
| 2124 | } | ||
| 2125 | else { | ||
| 2126 | tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + | ||
| 2127 | (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> | ||
| 2128 | ptr_CHDLC_Tx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); | ||
| 2129 | |||
| 2130 | rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + | ||
| 2131 | (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> | ||
| 2132 | ptr_CHDLC_Rx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); | ||
| 2133 | |||
| 2134 | /* Setup Head and Tails for buffers */ | ||
| 2135 | card->u.c.txbuf_base = (void *)(card->hw.dpmbase + | ||
| 2136 | (tx_config->base_addr_Tx_status_elements % SDLA_WINDOWSIZE)); | ||
| 2137 | card->u.c.txbuf_last = | ||
| 2138 | (CHDLC_DATA_TX_STATUS_EL_STRUCT *)card->u.c.txbuf_base | ||
| 2139 | + (tx_config->number_Tx_status_elements - 1); | ||
| 2140 | card->u.c.rxbuf_base = (void *)(card->hw.dpmbase + | ||
| 2141 | (rx_config->base_addr_Rx_status_elements % SDLA_WINDOWSIZE)); | ||
| 2142 | card->u.c.rxbuf_last = | ||
| 2143 | (CHDLC_DATA_RX_STATUS_EL_STRUCT *)card->u.c.rxbuf_base | ||
| 2144 | + (rx_config->number_Rx_status_elements - 1); | ||
| 2145 | |||
| 2146 | /* Set up next pointer to be used */ | ||
| 2147 | card->u.c.txbuf = (void *)(card->hw.dpmbase + | ||
| 2148 | (tx_config->next_Tx_status_element_to_use % SDLA_WINDOWSIZE)); | ||
| 2149 | card->u.c.rxmb = (void *)(card->hw.dpmbase + | ||
| 2150 | (rx_config->next_Rx_status_element_to_use % SDLA_WINDOWSIZE)); | ||
| 2151 | } | ||
| 2152 | |||
| 2153 | /* Setup Actual Buffer Start and end addresses */ | ||
| 2154 | card->u.c.rx_base = rx_config->base_addr_Rx_buffer; | ||
| 2155 | card->u.c.rx_top = rx_config->end_addr_Rx_buffer; | ||
| 2156 | |||
| 2157 | } | ||
| 2158 | |||
| 2159 | /*============================================================================= | ||
| 2160 | * Perform Interrupt Test by running READ_CHDLC_CODE_VERSION command MAX_INTR | ||
| 2161 | * _TEST_COUNTER times. | ||
| 2162 | */ | ||
| 2163 | static int intr_test( sdla_t* card) | ||
| 2164 | { | ||
| 2165 | CHDLC_MAILBOX_STRUCT* mb = card->mbox; | ||
| 2166 | int err,i; | ||
| 2167 | |||
| 2168 | Intr_test_counter = 0; | ||
| 2169 | |||
| 2170 | /* The critical flag is unset because during initialization (if_open) | ||
| 2171 | * we want the interrupts to be enabled so that when the wpc_isr is | ||
| 2172 | * called it does not exit due to critical flag set. | ||
| 2173 | */ | ||
| 2174 | |||
| 2175 | err = chdlc_set_intr_mode(card, APP_INT_ON_COMMAND_COMPLETE); | ||
| 2176 | |||
| 2177 | if (err == CMD_OK) { | ||
| 2178 | for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) { | ||
| 2179 | mb->buffer_length = 0; | ||
| 2180 | mb->command = READ_CHDLC_CODE_VERSION; | ||
| 2181 | err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; | ||
| 2182 | } | ||
| 2183 | } | ||
| 2184 | else { | ||
| 2185 | return err; | ||
| 2186 | } | ||
| 2187 | |||
| 2188 | err = chdlc_set_intr_mode(card, 0); | ||
| 2189 | |||
| 2190 | if (err != CMD_OK) | ||
| 2191 | return err; | ||
| 2192 | |||
| 2193 | return 0; | ||
| 2194 | } | ||
| 2195 | |||
| 2196 | /*============================================================================== | ||
| 2197 | * Determine what type of UDP call it is. CPIPEAB ? | ||
| 2198 | */ | ||
| 2199 | static int udp_pkt_type(struct sk_buff *skb, sdla_t* card) | ||
| 2200 | { | ||
| 2201 | chdlc_udp_pkt_t *chdlc_udp_pkt = (chdlc_udp_pkt_t *)skb->data; | ||
| 2202 | |||
| 2203 | if (!strncmp(chdlc_udp_pkt->wp_mgmt.signature,UDPMGMT_SIGNATURE,8) && | ||
| 2204 | (chdlc_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) && | ||
| 2205 | (chdlc_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && | ||
| 2206 | (chdlc_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) { | ||
| 2207 | return UDP_CPIPE_TYPE; | ||
| 2208 | } | ||
| 2209 | else return UDP_INVALID_TYPE; | ||
| 2210 | } | ||
| 2211 | |||
| 2212 | /*============================================================================ | ||
| 2213 | * Set PORT state. | ||
| 2214 | */ | ||
| 2215 | static void port_set_state (sdla_t *card, int state) | ||
| 2216 | { | ||
| 2217 | struct net_device *dev = card->wandev.dev; | ||
| 2218 | chdlc_private_area_t *chdlc_priv_area = dev->priv; | ||
| 2219 | |||
| 2220 | if (card->u.c.state != state) | ||
| 2221 | { | ||
| 2222 | switch (state) | ||
| 2223 | { | ||
| 2224 | case WAN_CONNECTED: | ||
| 2225 | printk (KERN_INFO "%s: HDLC link connected!\n", | ||
| 2226 | card->devname); | ||
| 2227 | break; | ||
| 2228 | |||
| 2229 | case WAN_CONNECTING: | ||
| 2230 | printk (KERN_INFO "%s: HDLC link connecting...\n", | ||
| 2231 | card->devname); | ||
| 2232 | break; | ||
| 2233 | |||
| 2234 | case WAN_DISCONNECTED: | ||
| 2235 | printk (KERN_INFO "%s: HDLC link disconnected!\n", | ||
| 2236 | card->devname); | ||
| 2237 | break; | ||
| 2238 | } | ||
| 2239 | |||
| 2240 | card->wandev.state = card->u.c.state = state; | ||
| 2241 | chdlc_priv_area->common.state = state; | ||
| 2242 | } | ||
| 2243 | } | ||
| 2244 | |||
| 2245 | void s508_lock (sdla_t *card, unsigned long *smp_flags) | ||
| 2246 | { | ||
| 2247 | spin_lock_irqsave(&card->wandev.lock, *smp_flags); | ||
| 2248 | if (card->next){ | ||
| 2249 | /* It is ok to use spin_lock here, since we | ||
| 2250 | * already turned off interrupts */ | ||
| 2251 | spin_lock(&card->next->wandev.lock); | ||
| 2252 | } | ||
| 2253 | } | ||
| 2254 | |||
| 2255 | void s508_unlock (sdla_t *card, unsigned long *smp_flags) | ||
| 2256 | { | ||
| 2257 | if (card->next){ | ||
| 2258 | spin_unlock(&card->next->wandev.lock); | ||
| 2259 | } | ||
| 2260 | spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); | ||
| 2261 | } | ||
| 2262 | |||
| 2263 | |||
| 2264 | |||
| 2265 | /*=========================================================================== | ||
| 2266 | * config_chdlc | ||
| 2267 | * | ||
| 2268 | * Configure the chdlc protocol and enable communications. | ||
| 2269 | * | ||
| 2270 | * The if_open() function binds this function to the poll routine. | ||
| 2271 | * Therefore, this function will run every time the chdlc interface | ||
| 2272 | * is brought up. We cannot run this function from the if_open | ||
| 2273 | * because if_open does not have access to the remote IP address. | ||
| 2274 | * | ||
| 2275 | * If the communications are not enabled, proceed to configure | ||
| 2276 | * the card and enable communications. | ||
| 2277 | * | ||
| 2278 | * If the communications are enabled, it means that the interface | ||
| 2279 | * was shutdown by ether the user or driver. In this case, we | ||
| 2280 | * have to check that the IP addresses have not changed. If | ||
| 2281 | * the IP addresses have changed, we have to reconfigure the firmware | ||
| 2282 | * and update the changed IP addresses. Otherwise, just exit. | ||
| 2283 | * | ||
| 2284 | */ | ||
| 2285 | |||
| 2286 | static int config_chdlc (sdla_t *card) | ||
| 2287 | { | ||
| 2288 | struct net_device *dev = card->wandev.dev; | ||
| 2289 | SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; | ||
| 2290 | |||
| 2291 | if (card->u.c.comm_enabled){ | ||
| 2292 | chdlc_comm_disable(card); | ||
| 2293 | port_set_state(card, WAN_DISCONNECTED); | ||
| 2294 | } | ||
| 2295 | |||
| 2296 | if (set_chdlc_config(card)) { | ||
| 2297 | printk(KERN_INFO "%s: CHDLC Configuration Failed!\n", | ||
| 2298 | card->devname); | ||
| 2299 | return 0; | ||
| 2300 | } | ||
| 2301 | init_chdlc_tx_rx_buff(card, dev); | ||
| 2302 | |||
| 2303 | /* Set interrupt mode and mask */ | ||
| 2304 | if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | | ||
| 2305 | APP_INT_ON_GLOBAL_EXCEP_COND | | ||
| 2306 | APP_INT_ON_TX_FRAME | | ||
| 2307 | APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){ | ||
| 2308 | printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", | ||
| 2309 | card->devname); | ||
| 2310 | return 0; | ||
| 2311 | } | ||
| 2312 | |||
| 2313 | |||
| 2314 | /* Mask the Transmit and Timer interrupt */ | ||
| 2315 | flags->interrupt_info_struct.interrupt_permission &= | ||
| 2316 | ~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER); | ||
| 2317 | |||
| 2318 | |||
| 2319 | if (chdlc_comm_enable(card) != 0) { | ||
| 2320 | printk(KERN_INFO "%s: Failed to enable chdlc communications!\n", | ||
| 2321 | card->devname); | ||
| 2322 | flags->interrupt_info_struct.interrupt_permission = 0; | ||
| 2323 | card->u.c.comm_enabled=0; | ||
| 2324 | chdlc_set_intr_mode(card,0); | ||
| 2325 | return 0; | ||
| 2326 | } | ||
| 2327 | |||
| 2328 | /* Initialize Rx/Tx buffer control fields */ | ||
| 2329 | port_set_state(card, WAN_CONNECTING); | ||
| 2330 | return 0; | ||
| 2331 | } | ||
| 2332 | |||
| 2333 | |||
| 2334 | static void send_ppp_term_request(struct net_device *dev) | ||
| 2335 | { | ||
| 2336 | struct sk_buff *new_skb; | ||
| 2337 | unsigned char *buf; | ||
| 2338 | |||
| 2339 | if ((new_skb = dev_alloc_skb(8)) != NULL) { | ||
| 2340 | /* copy data into new_skb */ | ||
| 2341 | |||
| 2342 | buf = skb_put(new_skb, 8); | ||
| 2343 | sprintf(buf,"%c%c%c%c%c%c%c%c", 0xFF,0x03,0xC0,0x21,0x05,0x98,0x00,0x07); | ||
| 2344 | |||
| 2345 | /* Decapsulate pkt and pass it up the protocol stack */ | ||
| 2346 | new_skb->protocol = htons(ETH_P_WAN_PPP); | ||
| 2347 | new_skb->dev = dev; | ||
| 2348 | new_skb->mac.raw = new_skb->data; | ||
| 2349 | |||
| 2350 | netif_rx(new_skb); | ||
| 2351 | dev->last_rx = jiffies; | ||
| 2352 | } | ||
| 2353 | } | ||
| 2354 | |||
| 2355 | |||
| 2356 | MODULE_LICENSE("GPL"); | ||
| 2357 | |||
| 2358 | /****** End ****************************************************************/ | ||
