diff options
| author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
| commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
| tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/net/arcnet | |
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/net/arcnet')
| -rw-r--r-- | drivers/net/arcnet/Kconfig | 140 | ||||
| -rw-r--r-- | drivers/net/arcnet/Makefile | 14 | ||||
| -rw-r--r-- | drivers/net/arcnet/arc-rawmode.c | 204 | ||||
| -rw-r--r-- | drivers/net/arcnet/arc-rimi.c | 368 | ||||
| -rw-r--r-- | drivers/net/arcnet/arcnet.c | 1102 | ||||
| -rw-r--r-- | drivers/net/arcnet/capmode.c | 296 | ||||
| -rw-r--r-- | drivers/net/arcnet/com20020-isa.c | 219 | ||||
| -rw-r--r-- | drivers/net/arcnet/com20020-pci.c | 189 | ||||
| -rw-r--r-- | drivers/net/arcnet/com20020.c | 357 | ||||
| -rw-r--r-- | drivers/net/arcnet/com90io.c | 435 | ||||
| -rw-r--r-- | drivers/net/arcnet/com90xx.c | 646 | ||||
| -rw-r--r-- | drivers/net/arcnet/rfc1051.c | 253 | ||||
| -rw-r--r-- | drivers/net/arcnet/rfc1201.c | 549 |
13 files changed, 4772 insertions, 0 deletions
diff --git a/drivers/net/arcnet/Kconfig b/drivers/net/arcnet/Kconfig new file mode 100644 index 00000000000..948de2532a1 --- /dev/null +++ b/drivers/net/arcnet/Kconfig | |||
| @@ -0,0 +1,140 @@ | |||
| 1 | # | ||
| 2 | # Arcnet configuration | ||
| 3 | # | ||
| 4 | |||
| 5 | menu "ARCnet devices" | ||
| 6 | depends on NETDEVICES && (ISA || PCI) | ||
| 7 | |||
| 8 | config ARCNET | ||
| 9 | tristate "ARCnet support" | ||
| 10 | ---help--- | ||
| 11 | If you have a network card of this type, say Y and check out the | ||
| 12 | (arguably) beautiful poetry in | ||
| 13 | <file:Documentation/networking/arcnet.txt>. | ||
| 14 | |||
| 15 | You need both this driver, and the driver for the particular ARCnet | ||
| 16 | chipset of your card. If you don't know, then it's probably a | ||
| 17 | COM90xx type card, so say Y (or M) to "ARCnet COM90xx chipset | ||
| 18 | support" below. | ||
| 19 | |||
| 20 | You might also want to have a look at the Ethernet-HOWTO, available | ||
| 21 | from <http://www.tldp.org/docs.html#howto>(even though ARCnet | ||
| 22 | is not really Ethernet). | ||
| 23 | |||
| 24 | To compile this driver as a module, choose M here and read | ||
| 25 | <file:Documentation/networking/net-modules.txt>. The module will | ||
| 26 | be called arcnet. | ||
| 27 | |||
| 28 | config ARCNET_1201 | ||
| 29 | tristate "Enable standard ARCNet packet format (RFC 1201)" | ||
| 30 | depends on ARCNET | ||
| 31 | help | ||
| 32 | This allows you to use RFC1201 with your ARCnet card via the virtual | ||
| 33 | arc0 device. You need to say Y here to communicate with | ||
| 34 | industry-standard RFC1201 implementations, like the arcether.com | ||
| 35 | packet driver or most DOS/Windows ODI drivers. Please read the | ||
| 36 | ARCnet documentation in <file:Documentation/networking/arcnet.txt> | ||
| 37 | for more information about using arc0. | ||
| 38 | |||
| 39 | config ARCNET_1051 | ||
| 40 | tristate "Enable old ARCNet packet format (RFC 1051)" | ||
| 41 | depends on ARCNET | ||
| 42 | ---help--- | ||
| 43 | This allows you to use RFC1051 with your ARCnet card via the virtual | ||
| 44 | arc0s device. You only need arc0s if you want to talk to ARCnet | ||
| 45 | software complying with the "old" standard, specifically, the DOS | ||
| 46 | arcnet.com packet driver, Amigas running AmiTCP, and some variants | ||
| 47 | of NetBSD. You do not need to say Y here to communicate with | ||
| 48 | industry-standard RFC1201 implementations, like the arcether.com | ||
| 49 | packet driver or most DOS/Windows ODI drivers. RFC1201 is included | ||
| 50 | automatically as the arc0 device. Please read the ARCnet | ||
| 51 | documentation in <file:Documentation/networking/arcnet.txt> for more | ||
| 52 | information about using arc0e and arc0s. | ||
| 53 | |||
| 54 | config ARCNET_RAW | ||
| 55 | tristate "Enable raw mode packet interface" | ||
| 56 | depends on ARCNET | ||
| 57 | help | ||
| 58 | ARCnet "raw mode" packet encapsulation, no soft headers. Unlikely | ||
| 59 | to work unless talking to a copy of the same Linux arcnet driver, | ||
| 60 | but perhaps marginally faster in that case. | ||
| 61 | |||
| 62 | config ARCNET_CAP | ||
| 63 | tristate "Enable CAP mode packet interface" | ||
| 64 | depends on ARCNET | ||
| 65 | help | ||
| 66 | ARCnet "cap mode" packet encapsulation. Used to get the hardware | ||
| 67 | acknowledge back to userspace. After the initial protocol byte every | ||
| 68 | packet is stuffed with an extra 4 byte "cookie" which doesn't | ||
| 69 | actually appear on the network. After transmit the driver will send | ||
| 70 | back a packet with protocol byte 0 containing the status of the | ||
| 71 | transmition: | ||
| 72 | 0=no hardware acknowledge | ||
| 73 | 1=excessive nak | ||
| 74 | 2=transmition accepted by the reciever hardware | ||
| 75 | |||
| 76 | Received packets are also stuffed with the extra 4 bytes but it will | ||
| 77 | be random data. | ||
| 78 | |||
| 79 | Cap only listens to protocol 1-8. | ||
| 80 | |||
| 81 | config ARCNET_COM90xx | ||
| 82 | tristate "ARCnet COM90xx (normal) chipset driver" | ||
| 83 | depends on ARCNET | ||
| 84 | help | ||
| 85 | This is the chipset driver for the standard COM90xx cards. If you | ||
| 86 | have always used the old ARCnet driver without knowing what type of | ||
| 87 | card you had, this is probably the one for you. | ||
| 88 | |||
| 89 | To compile this driver as a module, choose M here and read | ||
| 90 | <file:Documentation/networking/net-modules.txt>. The module will | ||
| 91 | be called com90xx. | ||
| 92 | |||
| 93 | config ARCNET_COM90xxIO | ||
| 94 | tristate "ARCnet COM90xx (IO mapped) chipset driver" | ||
| 95 | depends on ARCNET | ||
| 96 | ---help--- | ||
| 97 | This is the chipset driver for the COM90xx cards, using them in | ||
| 98 | IO-mapped mode instead of memory-mapped mode. This is slower than | ||
| 99 | the normal driver. Only use it if your card doesn't support shared | ||
| 100 | memory. | ||
| 101 | |||
| 102 | To compile this driver as a module, choose M here and read | ||
| 103 | <file:Documentation/networking/net-modules.txt>. The module will | ||
| 104 | be called com90io. | ||
| 105 | |||
| 106 | config ARCNET_RIM_I | ||
| 107 | tristate "ARCnet COM90xx (RIM I) chipset driver" | ||
| 108 | depends on ARCNET | ||
| 109 | ---help--- | ||
| 110 | This is yet another chipset driver for the COM90xx cards, but this | ||
| 111 | time only using memory-mapped mode, and no IO ports at all. This | ||
| 112 | driver is completely untested, so if you have one of these cards, | ||
| 113 | please mail <dwmw2@infradead.org>, especially if it works! | ||
| 114 | |||
| 115 | To compile this driver as a module, choose M here and read | ||
| 116 | <file:Documentation/networking/net-modules.txt>. The module will | ||
| 117 | be called arc-rimi. | ||
| 118 | |||
| 119 | config ARCNET_COM20020 | ||
| 120 | tristate "ARCnet COM20020 chipset driver" | ||
| 121 | depends on ARCNET | ||
| 122 | help | ||
| 123 | This is the driver for the new COM20020 chipset. It supports such | ||
| 124 | things as promiscuous mode, so packet sniffing is possible, and | ||
| 125 | extra diagnostic information. | ||
| 126 | |||
| 127 | To compile this driver as a module, choose M here and read | ||
| 128 | <file:Documentation/networking/net-modules.txt>. The module will | ||
| 129 | be called com20020. | ||
| 130 | |||
| 131 | config ARCNET_COM20020_ISA | ||
| 132 | tristate "Support for COM20020 on ISA" | ||
| 133 | depends on ARCNET_COM20020 && ISA | ||
| 134 | |||
| 135 | config ARCNET_COM20020_PCI | ||
| 136 | tristate "Support for COM20020 on PCI" | ||
| 137 | depends on ARCNET_COM20020 && PCI | ||
| 138 | |||
| 139 | endmenu | ||
| 140 | |||
diff --git a/drivers/net/arcnet/Makefile b/drivers/net/arcnet/Makefile new file mode 100644 index 00000000000..5861af543d4 --- /dev/null +++ b/drivers/net/arcnet/Makefile | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | # Makefile for linux/drivers/net/arcnet | ||
| 2 | # | ||
| 3 | |||
| 4 | obj-$(CONFIG_ARCNET) += arcnet.o | ||
| 5 | obj-$(CONFIG_ARCNET_1201) += rfc1201.o | ||
| 6 | obj-$(CONFIG_ARCNET_1051) += rfc1051.o | ||
| 7 | obj-$(CONFIG_ARCNET_RAW) += arc-rawmode.o | ||
| 8 | obj-$(CONFIG_ARCNET_CAP) += capmode.o | ||
| 9 | obj-$(CONFIG_ARCNET_COM90xx) += com90xx.o | ||
| 10 | obj-$(CONFIG_ARCNET_COM90xxIO) += com90io.o | ||
| 11 | obj-$(CONFIG_ARCNET_RIM_I) += arc-rimi.o | ||
| 12 | obj-$(CONFIG_ARCNET_COM20020) += com20020.o | ||
| 13 | obj-$(CONFIG_ARCNET_COM20020_ISA) += com20020-isa.o | ||
| 14 | obj-$(CONFIG_ARCNET_COM20020_PCI) += com20020-pci.o | ||
diff --git a/drivers/net/arcnet/arc-rawmode.c b/drivers/net/arcnet/arc-rawmode.c new file mode 100644 index 00000000000..e1ea29b0cd1 --- /dev/null +++ b/drivers/net/arcnet/arc-rawmode.c | |||
| @@ -0,0 +1,204 @@ | |||
| 1 | /* | ||
| 2 | * Linux ARCnet driver - "raw mode" packet encapsulation (no soft headers) | ||
| 3 | * | ||
| 4 | * Written 1994-1999 by Avery Pennarun. | ||
| 5 | * Derived from skeleton.c by Donald Becker. | ||
| 6 | * | ||
| 7 | * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) | ||
| 8 | * for sponsoring the further development of this driver. | ||
| 9 | * | ||
| 10 | * ********************** | ||
| 11 | * | ||
| 12 | * The original copyright of skeleton.c was as follows: | ||
| 13 | * | ||
| 14 | * skeleton.c Written 1993 by Donald Becker. | ||
| 15 | * Copyright 1993 United States Government as represented by the | ||
| 16 | * Director, National Security Agency. This software may only be used | ||
| 17 | * and distributed according to the terms of the GNU General Public License as | ||
| 18 | * modified by SRC, incorporated herein by reference. | ||
| 19 | * | ||
| 20 | * ********************** | ||
| 21 | * | ||
| 22 | * For more details, see drivers/net/arcnet.c | ||
| 23 | * | ||
| 24 | * ********************** | ||
| 25 | */ | ||
| 26 | |||
| 27 | #include <linux/module.h> | ||
| 28 | #include <linux/init.h> | ||
| 29 | #include <linux/if_arp.h> | ||
| 30 | #include <net/arp.h> | ||
| 31 | #include <linux/netdevice.h> | ||
| 32 | #include <linux/skbuff.h> | ||
| 33 | #include <linux/arcdevice.h> | ||
| 34 | |||
| 35 | #define VERSION "arcnet: raw mode (`r') encapsulation support loaded.\n" | ||
| 36 | |||
| 37 | |||
| 38 | static void rx(struct net_device *dev, int bufnum, | ||
| 39 | struct archdr *pkthdr, int length); | ||
| 40 | static int build_header(struct sk_buff *skb, struct net_device *dev, | ||
| 41 | unsigned short type, uint8_t daddr); | ||
| 42 | static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, | ||
| 43 | int bufnum); | ||
| 44 | |||
| 45 | struct ArcProto rawmode_proto = | ||
| 46 | { | ||
| 47 | .suffix = 'r', | ||
| 48 | .mtu = XMTU, | ||
| 49 | .rx = rx, | ||
| 50 | .build_header = build_header, | ||
| 51 | .prepare_tx = prepare_tx, | ||
| 52 | .continue_tx = NULL, | ||
| 53 | .ack_tx = NULL | ||
| 54 | }; | ||
| 55 | |||
| 56 | |||
| 57 | static int __init arcnet_raw_init(void) | ||
| 58 | { | ||
| 59 | int count; | ||
| 60 | |||
| 61 | printk(VERSION); | ||
| 62 | |||
| 63 | for (count = 0; count < 256; count++) | ||
| 64 | if (arc_proto_map[count] == arc_proto_default) | ||
| 65 | arc_proto_map[count] = &rawmode_proto; | ||
| 66 | |||
| 67 | /* for raw mode, we only set the bcast proto if there's no better one */ | ||
| 68 | if (arc_bcast_proto == arc_proto_default) | ||
| 69 | arc_bcast_proto = &rawmode_proto; | ||
| 70 | |||
| 71 | arc_proto_default = &rawmode_proto; | ||
| 72 | return 0; | ||
| 73 | } | ||
| 74 | |||
| 75 | static void __exit arcnet_raw_exit(void) | ||
| 76 | { | ||
| 77 | arcnet_unregister_proto(&rawmode_proto); | ||
| 78 | } | ||
| 79 | |||
| 80 | module_init(arcnet_raw_init); | ||
| 81 | module_exit(arcnet_raw_exit); | ||
| 82 | |||
| 83 | MODULE_LICENSE("GPL"); | ||
| 84 | |||
| 85 | |||
| 86 | /* packet receiver */ | ||
| 87 | static void rx(struct net_device *dev, int bufnum, | ||
| 88 | struct archdr *pkthdr, int length) | ||
| 89 | { | ||
| 90 | struct arcnet_local *lp = dev->priv; | ||
| 91 | struct sk_buff *skb; | ||
| 92 | struct archdr *pkt = pkthdr; | ||
| 93 | int ofs; | ||
| 94 | |||
| 95 | BUGMSG(D_DURING, "it's a raw packet (length=%d)\n", length); | ||
| 96 | |||
| 97 | if (length >= MinTU) | ||
| 98 | ofs = 512 - length; | ||
| 99 | else | ||
| 100 | ofs = 256 - length; | ||
| 101 | |||
| 102 | skb = alloc_skb(length + ARC_HDR_SIZE, GFP_ATOMIC); | ||
| 103 | if (skb == NULL) { | ||
| 104 | BUGMSG(D_NORMAL, "Memory squeeze, dropping packet.\n"); | ||
| 105 | lp->stats.rx_dropped++; | ||
| 106 | return; | ||
| 107 | } | ||
| 108 | skb_put(skb, length + ARC_HDR_SIZE); | ||
| 109 | skb->dev = dev; | ||
| 110 | |||
| 111 | pkt = (struct archdr *) skb->data; | ||
| 112 | |||
| 113 | skb->mac.raw = skb->data; | ||
| 114 | skb_pull(skb, ARC_HDR_SIZE); | ||
| 115 | |||
| 116 | /* up to sizeof(pkt->soft) has already been copied from the card */ | ||
| 117 | memcpy(pkt, pkthdr, sizeof(struct archdr)); | ||
| 118 | if (length > sizeof(pkt->soft)) | ||
| 119 | lp->hw.copy_from_card(dev, bufnum, ofs + sizeof(pkt->soft), | ||
| 120 | pkt->soft.raw + sizeof(pkt->soft), | ||
| 121 | length - sizeof(pkt->soft)); | ||
| 122 | |||
| 123 | BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx"); | ||
| 124 | |||
| 125 | skb->protocol = __constant_htons(ETH_P_ARCNET); | ||
| 126 | ; | ||
| 127 | netif_rx(skb); | ||
| 128 | dev->last_rx = jiffies; | ||
| 129 | } | ||
| 130 | |||
| 131 | |||
| 132 | /* | ||
| 133 | * Create the ARCnet hard/soft headers for raw mode. | ||
| 134 | * There aren't any soft headers in raw mode - not even the protocol id. | ||
| 135 | */ | ||
| 136 | static int build_header(struct sk_buff *skb, struct net_device *dev, | ||
| 137 | unsigned short type, uint8_t daddr) | ||
| 138 | { | ||
| 139 | int hdr_size = ARC_HDR_SIZE; | ||
| 140 | struct archdr *pkt = (struct archdr *) skb_push(skb, hdr_size); | ||
| 141 | |||
| 142 | /* | ||
| 143 | * Set the source hardware address. | ||
| 144 | * | ||
| 145 | * This is pretty pointless for most purposes, but it can help in | ||
| 146 | * debugging. ARCnet does not allow us to change the source address in | ||
| 147 | * the actual packet sent) | ||
| 148 | */ | ||
| 149 | pkt->hard.source = *dev->dev_addr; | ||
| 150 | |||
| 151 | /* see linux/net/ethernet/eth.c to see where I got the following */ | ||
| 152 | |||
| 153 | if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) { | ||
| 154 | /* | ||
| 155 | * FIXME: fill in the last byte of the dest ipaddr here to better | ||
| 156 | * comply with RFC1051 in "noarp" mode. | ||
| 157 | */ | ||
| 158 | pkt->hard.dest = 0; | ||
| 159 | return hdr_size; | ||
| 160 | } | ||
| 161 | /* otherwise, just fill it in and go! */ | ||
| 162 | pkt->hard.dest = daddr; | ||
| 163 | |||
| 164 | return hdr_size; /* success */ | ||
| 165 | } | ||
| 166 | |||
| 167 | |||
| 168 | static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, | ||
| 169 | int bufnum) | ||
| 170 | { | ||
| 171 | struct arcnet_local *lp = dev->priv; | ||
| 172 | struct arc_hardware *hard = &pkt->hard; | ||
| 173 | int ofs; | ||
| 174 | |||
| 175 | BUGMSG(D_DURING, "prepare_tx: txbufs=%d/%d/%d\n", | ||
| 176 | lp->next_tx, lp->cur_tx, bufnum); | ||
| 177 | |||
| 178 | length -= ARC_HDR_SIZE; /* hard header is not included in packet length */ | ||
| 179 | |||
| 180 | if (length > XMTU) { | ||
| 181 | /* should never happen! other people already check for this. */ | ||
| 182 | BUGMSG(D_NORMAL, "Bug! prepare_tx with size %d (> %d)\n", | ||
| 183 | length, XMTU); | ||
| 184 | length = XMTU; | ||
| 185 | } | ||
| 186 | if (length > MinTU) { | ||
| 187 | hard->offset[0] = 0; | ||
| 188 | hard->offset[1] = ofs = 512 - length; | ||
| 189 | } else if (length > MTU) { | ||
| 190 | hard->offset[0] = 0; | ||
| 191 | hard->offset[1] = ofs = 512 - length - 3; | ||
| 192 | } else | ||
| 193 | hard->offset[0] = ofs = 256 - length; | ||
| 194 | |||
| 195 | BUGMSG(D_DURING, "prepare_tx: length=%d ofs=%d\n", | ||
| 196 | length,ofs); | ||
| 197 | |||
| 198 | lp->hw.copy_to_card(dev, bufnum, 0, hard, ARC_HDR_SIZE); | ||
| 199 | lp->hw.copy_to_card(dev, bufnum, ofs, &pkt->soft, length); | ||
| 200 | |||
| 201 | lp->lastload_dest = hard->dest; | ||
| 202 | |||
| 203 | return 1; /* done */ | ||
| 204 | } | ||
diff --git a/drivers/net/arcnet/arc-rimi.c b/drivers/net/arcnet/arc-rimi.c new file mode 100644 index 00000000000..38c3f033f73 --- /dev/null +++ b/drivers/net/arcnet/arc-rimi.c | |||
| @@ -0,0 +1,368 @@ | |||
| 1 | /* | ||
| 2 | * Linux ARCnet driver - "RIM I" (entirely mem-mapped) cards | ||
| 3 | * | ||
| 4 | * Written 1994-1999 by Avery Pennarun. | ||
| 5 | * Written 1999-2000 by Martin Mares <mj@ucw.cz>. | ||
| 6 | * Derived from skeleton.c by Donald Becker. | ||
| 7 | * | ||
| 8 | * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) | ||
| 9 | * for sponsoring the further development of this driver. | ||
| 10 | * | ||
| 11 | * ********************** | ||
| 12 | * | ||
| 13 | * The original copyright of skeleton.c was as follows: | ||
| 14 | * | ||
| 15 | * skeleton.c Written 1993 by Donald Becker. | ||
| 16 | * Copyright 1993 United States Government as represented by the | ||
| 17 | * Director, National Security Agency. This software may only be used | ||
| 18 | * and distributed according to the terms of the GNU General Public License as | ||
| 19 | * modified by SRC, incorporated herein by reference. | ||
| 20 | * | ||
| 21 | * ********************** | ||
| 22 | * | ||
| 23 | * For more details, see drivers/net/arcnet.c | ||
| 24 | * | ||
| 25 | * ********************** | ||
| 26 | */ | ||
| 27 | #include <linux/kernel.h> | ||
| 28 | #include <linux/module.h> | ||
| 29 | #include <linux/moduleparam.h> | ||
| 30 | #include <linux/ioport.h> | ||
| 31 | #include <linux/slab.h> | ||
| 32 | #include <linux/delay.h> | ||
| 33 | #include <linux/netdevice.h> | ||
| 34 | #include <linux/bootmem.h> | ||
| 35 | #include <linux/init.h> | ||
| 36 | #include <asm/io.h> | ||
| 37 | #include <linux/arcdevice.h> | ||
| 38 | |||
| 39 | |||
| 40 | #define VERSION "arcnet: RIM I (entirely mem-mapped) support\n" | ||
| 41 | |||
| 42 | |||
| 43 | /* Internal function declarations */ | ||
| 44 | |||
| 45 | static int arcrimi_probe(struct net_device *dev); | ||
| 46 | static int arcrimi_found(struct net_device *dev); | ||
| 47 | static void arcrimi_command(struct net_device *dev, int command); | ||
| 48 | static int arcrimi_status(struct net_device *dev); | ||
| 49 | static void arcrimi_setmask(struct net_device *dev, int mask); | ||
| 50 | static int arcrimi_reset(struct net_device *dev, int really_reset); | ||
| 51 | static void arcrimi_copy_to_card(struct net_device *dev, int bufnum, int offset, | ||
| 52 | void *buf, int count); | ||
| 53 | static void arcrimi_copy_from_card(struct net_device *dev, int bufnum, int offset, | ||
| 54 | void *buf, int count); | ||
| 55 | |||
| 56 | /* Handy defines for ARCnet specific stuff */ | ||
| 57 | |||
| 58 | /* Amount of I/O memory used by the card */ | ||
| 59 | #define BUFFER_SIZE (512) | ||
| 60 | #define MIRROR_SIZE (BUFFER_SIZE*4) | ||
| 61 | |||
| 62 | /* COM 9026 controller chip --> ARCnet register addresses */ | ||
| 63 | #define _INTMASK (ioaddr+0) /* writable */ | ||
| 64 | #define _STATUS (ioaddr+0) /* readable */ | ||
| 65 | #define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */ | ||
| 66 | #define _RESET (ioaddr+8) /* software reset (on read) */ | ||
| 67 | #define _MEMDATA (ioaddr+12) /* Data port for IO-mapped memory */ | ||
| 68 | #define _ADDR_HI (ioaddr+15) /* Control registers for said */ | ||
| 69 | #define _ADDR_LO (ioaddr+14) | ||
| 70 | #define _CONFIG (ioaddr+2) /* Configuration register */ | ||
| 71 | |||
| 72 | #undef ASTATUS | ||
| 73 | #undef ACOMMAND | ||
| 74 | #undef AINTMASK | ||
| 75 | |||
| 76 | #define ASTATUS() readb(_STATUS) | ||
| 77 | #define ACOMMAND(cmd) writeb((cmd),_COMMAND) | ||
| 78 | #define AINTMASK(msk) writeb((msk),_INTMASK) | ||
| 79 | #define SETCONF() writeb(lp->config,_CONFIG) | ||
| 80 | |||
| 81 | |||
| 82 | /* | ||
| 83 | * We cannot probe for a RIM I card; one reason is I don't know how to reset | ||
| 84 | * them. In fact, we can't even get their node ID automatically. So, we | ||
| 85 | * need to be passed a specific shmem address, IRQ, and node ID. | ||
| 86 | */ | ||
| 87 | static int __init arcrimi_probe(struct net_device *dev) | ||
| 88 | { | ||
| 89 | BUGLVL(D_NORMAL) printk(VERSION); | ||
| 90 | BUGLVL(D_NORMAL) printk("E-mail me if you actually test the RIM I driver, please!\n"); | ||
| 91 | |||
| 92 | BUGMSG(D_NORMAL, "Given: node %02Xh, shmem %lXh, irq %d\n", | ||
| 93 | dev->dev_addr[0], dev->mem_start, dev->irq); | ||
| 94 | |||
| 95 | if (dev->mem_start <= 0 || dev->irq <= 0) { | ||
| 96 | BUGMSG(D_NORMAL, "No autoprobe for RIM I; you " | ||
| 97 | "must specify the shmem and irq!\n"); | ||
| 98 | return -ENODEV; | ||
| 99 | } | ||
| 100 | /* | ||
| 101 | * Grab the memory region at mem_start for BUFFER_SIZE bytes. | ||
| 102 | * Later in arcrimi_found() the real size will be determined | ||
| 103 | * and this reserve will be released and the correct size | ||
| 104 | * will be taken. | ||
| 105 | */ | ||
| 106 | if (!request_mem_region(dev->mem_start, BUFFER_SIZE, "arcnet (90xx)")) { | ||
| 107 | BUGMSG(D_NORMAL, "Card memory already allocated\n"); | ||
| 108 | return -ENODEV; | ||
| 109 | } | ||
| 110 | if (dev->dev_addr[0] == 0) { | ||
| 111 | release_mem_region(dev->mem_start, BUFFER_SIZE); | ||
| 112 | BUGMSG(D_NORMAL, "You need to specify your card's station " | ||
| 113 | "ID!\n"); | ||
| 114 | return -ENODEV; | ||
| 115 | } | ||
| 116 | return arcrimi_found(dev); | ||
| 117 | } | ||
| 118 | |||
| 119 | |||
| 120 | /* | ||
| 121 | * Set up the struct net_device associated with this card. Called after | ||
| 122 | * probing succeeds. | ||
| 123 | */ | ||
| 124 | static int __init arcrimi_found(struct net_device *dev) | ||
| 125 | { | ||
| 126 | struct arcnet_local *lp; | ||
| 127 | unsigned long first_mirror, last_mirror, shmem; | ||
| 128 | int mirror_size; | ||
| 129 | int err; | ||
| 130 | |||
| 131 | /* reserve the irq */ | ||
| 132 | if (request_irq(dev->irq, &arcnet_interrupt, 0, "arcnet (RIM I)", dev)) { | ||
| 133 | release_mem_region(dev->mem_start, BUFFER_SIZE); | ||
| 134 | BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq); | ||
| 135 | return -ENODEV; | ||
| 136 | } | ||
| 137 | |||
| 138 | shmem = dev->mem_start; | ||
| 139 | isa_writeb(TESTvalue, shmem); | ||
| 140 | isa_writeb(dev->dev_addr[0], shmem + 1); /* actually the node ID */ | ||
| 141 | |||
| 142 | /* find the real shared memory start/end points, including mirrors */ | ||
| 143 | |||
| 144 | /* guess the actual size of one "memory mirror" - the number of | ||
| 145 | * bytes between copies of the shared memory. On most cards, it's | ||
| 146 | * 2k (or there are no mirrors at all) but on some, it's 4k. | ||
| 147 | */ | ||
| 148 | mirror_size = MIRROR_SIZE; | ||
| 149 | if (isa_readb(shmem) == TESTvalue | ||
| 150 | && isa_readb(shmem - mirror_size) != TESTvalue | ||
| 151 | && isa_readb(shmem - 2 * mirror_size) == TESTvalue) | ||
| 152 | mirror_size *= 2; | ||
| 153 | |||
| 154 | first_mirror = last_mirror = shmem; | ||
| 155 | while (isa_readb(first_mirror) == TESTvalue) | ||
| 156 | first_mirror -= mirror_size; | ||
| 157 | first_mirror += mirror_size; | ||
| 158 | |||
| 159 | while (isa_readb(last_mirror) == TESTvalue) | ||
| 160 | last_mirror += mirror_size; | ||
| 161 | last_mirror -= mirror_size; | ||
| 162 | |||
| 163 | dev->mem_start = first_mirror; | ||
| 164 | dev->mem_end = last_mirror + MIRROR_SIZE - 1; | ||
| 165 | |||
| 166 | /* initialize the rest of the device structure. */ | ||
| 167 | |||
| 168 | lp = dev->priv; | ||
| 169 | lp->card_name = "RIM I"; | ||
| 170 | lp->hw.command = arcrimi_command; | ||
| 171 | lp->hw.status = arcrimi_status; | ||
| 172 | lp->hw.intmask = arcrimi_setmask; | ||
| 173 | lp->hw.reset = arcrimi_reset; | ||
| 174 | lp->hw.owner = THIS_MODULE; | ||
| 175 | lp->hw.copy_to_card = arcrimi_copy_to_card; | ||
| 176 | lp->hw.copy_from_card = arcrimi_copy_from_card; | ||
| 177 | |||
| 178 | /* | ||
| 179 | * re-reserve the memory region - arcrimi_probe() alloced this reqion | ||
| 180 | * but didn't know the real size. Free that region and then re-get | ||
| 181 | * with the correct size. There is a VERY slim chance this could | ||
| 182 | * fail. | ||
| 183 | */ | ||
| 184 | release_mem_region(shmem, BUFFER_SIZE); | ||
| 185 | if (!request_mem_region(dev->mem_start, | ||
| 186 | dev->mem_end - dev->mem_start + 1, | ||
| 187 | "arcnet (90xx)")) { | ||
| 188 | BUGMSG(D_NORMAL, "Card memory already allocated\n"); | ||
| 189 | goto err_free_irq; | ||
| 190 | } | ||
| 191 | |||
| 192 | lp->mem_start = ioremap(dev->mem_start, dev->mem_end - dev->mem_start + 1); | ||
| 193 | if (!lp->mem_start) { | ||
| 194 | BUGMSG(D_NORMAL, "Can't remap device memory!\n"); | ||
| 195 | goto err_release_mem; | ||
| 196 | } | ||
| 197 | |||
| 198 | /* get and check the station ID from offset 1 in shmem */ | ||
| 199 | dev->dev_addr[0] = readb(lp->mem_start + 1); | ||
| 200 | |||
| 201 | BUGMSG(D_NORMAL, "ARCnet RIM I: station %02Xh found at IRQ %d, " | ||
| 202 | "ShMem %lXh (%ld*%d bytes).\n", | ||
| 203 | dev->dev_addr[0], | ||
| 204 | dev->irq, dev->mem_start, | ||
| 205 | (dev->mem_end - dev->mem_start + 1) / mirror_size, mirror_size); | ||
| 206 | |||
| 207 | err = register_netdev(dev); | ||
| 208 | if (err) | ||
| 209 | goto err_unmap; | ||
| 210 | |||
| 211 | return 0; | ||
| 212 | |||
| 213 | err_unmap: | ||
| 214 | iounmap(lp->mem_start); | ||
| 215 | err_release_mem: | ||
| 216 | release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); | ||
| 217 | err_free_irq: | ||
| 218 | free_irq(dev->irq, dev); | ||
| 219 | return -EIO; | ||
| 220 | } | ||
| 221 | |||
| 222 | |||
| 223 | /* | ||
| 224 | * Do a hardware reset on the card, and set up necessary registers. | ||
| 225 | * | ||
| 226 | * This should be called as little as possible, because it disrupts the | ||
| 227 | * token on the network (causes a RECON) and requires a significant delay. | ||
| 228 | * | ||
| 229 | * However, it does make sure the card is in a defined state. | ||
| 230 | */ | ||
| 231 | static int arcrimi_reset(struct net_device *dev, int really_reset) | ||
| 232 | { | ||
| 233 | struct arcnet_local *lp = dev->priv; | ||
| 234 | void __iomem *ioaddr = lp->mem_start + 0x800; | ||
| 235 | |||
| 236 | BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n", dev->name, ASTATUS()); | ||
| 237 | |||
| 238 | if (really_reset) { | ||
| 239 | writeb(TESTvalue, ioaddr - 0x800); /* fake reset */ | ||
| 240 | return 0; | ||
| 241 | } | ||
| 242 | ACOMMAND(CFLAGScmd | RESETclear); /* clear flags & end reset */ | ||
| 243 | ACOMMAND(CFLAGScmd | CONFIGclear); | ||
| 244 | |||
| 245 | /* enable extended (512-byte) packets */ | ||
| 246 | ACOMMAND(CONFIGcmd | EXTconf); | ||
| 247 | |||
| 248 | /* done! return success. */ | ||
| 249 | return 0; | ||
| 250 | } | ||
| 251 | |||
| 252 | static void arcrimi_setmask(struct net_device *dev, int mask) | ||
| 253 | { | ||
| 254 | struct arcnet_local *lp = dev->priv; | ||
| 255 | void __iomem *ioaddr = lp->mem_start + 0x800; | ||
| 256 | |||
| 257 | AINTMASK(mask); | ||
| 258 | } | ||
| 259 | |||
| 260 | static int arcrimi_status(struct net_device *dev) | ||
| 261 | { | ||
| 262 | struct arcnet_local *lp = dev->priv; | ||
| 263 | void __iomem *ioaddr = lp->mem_start + 0x800; | ||
| 264 | |||
| 265 | return ASTATUS(); | ||
| 266 | } | ||
| 267 | |||
| 268 | static void arcrimi_command(struct net_device *dev, int cmd) | ||
| 269 | { | ||
| 270 | struct arcnet_local *lp = dev->priv; | ||
| 271 | void __iomem *ioaddr = lp->mem_start + 0x800; | ||
| 272 | |||
| 273 | ACOMMAND(cmd); | ||
| 274 | } | ||
| 275 | |||
| 276 | static void arcrimi_copy_to_card(struct net_device *dev, int bufnum, int offset, | ||
| 277 | void *buf, int count) | ||
| 278 | { | ||
| 279 | struct arcnet_local *lp = dev->priv; | ||
| 280 | void __iomem *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset; | ||
| 281 | TIME("memcpy_toio", count, memcpy_toio(memaddr, buf, count)); | ||
| 282 | } | ||
| 283 | |||
| 284 | |||
| 285 | static void arcrimi_copy_from_card(struct net_device *dev, int bufnum, int offset, | ||
| 286 | void *buf, int count) | ||
| 287 | { | ||
| 288 | struct arcnet_local *lp = dev->priv; | ||
| 289 | void __iomem *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset; | ||
| 290 | TIME("memcpy_fromio", count, memcpy_fromio(buf, memaddr, count)); | ||
| 291 | } | ||
| 292 | |||
| 293 | static int node; | ||
| 294 | static int io; /* use the insmod io= irq= node= options */ | ||
| 295 | static int irq; | ||
| 296 | static char device[9]; /* use eg. device=arc1 to change name */ | ||
| 297 | |||
| 298 | module_param(node, int, 0); | ||
| 299 | module_param(io, int, 0); | ||
| 300 | module_param(irq, int, 0); | ||
| 301 | module_param_string(device, device, sizeof(device), 0); | ||
| 302 | MODULE_LICENSE("GPL"); | ||
| 303 | |||
| 304 | static struct net_device *my_dev; | ||
| 305 | |||
| 306 | static int __init arc_rimi_init(void) | ||
| 307 | { | ||
| 308 | struct net_device *dev; | ||
| 309 | |||
| 310 | dev = alloc_arcdev(device); | ||
| 311 | if (!dev) | ||
| 312 | return -ENOMEM; | ||
| 313 | |||
| 314 | if (node && node != 0xff) | ||
| 315 | dev->dev_addr[0] = node; | ||
| 316 | |||
| 317 | dev->mem_start = io; | ||
| 318 | dev->irq = irq; | ||
| 319 | if (dev->irq == 2) | ||
| 320 | dev->irq = 9; | ||
| 321 | |||
| 322 | if (arcrimi_probe(dev)) { | ||
| 323 | free_netdev(dev); | ||
| 324 | return -EIO; | ||
| 325 | } | ||
| 326 | |||
| 327 | my_dev = dev; | ||
| 328 | return 0; | ||
| 329 | } | ||
| 330 | |||
| 331 | static void __exit arc_rimi_exit(void) | ||
| 332 | { | ||
| 333 | struct net_device *dev = my_dev; | ||
| 334 | struct arcnet_local *lp = dev->priv; | ||
| 335 | |||
| 336 | unregister_netdev(dev); | ||
| 337 | iounmap(lp->mem_start); | ||
| 338 | release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); | ||
| 339 | free_irq(dev->irq, dev); | ||
| 340 | free_netdev(dev); | ||
| 341 | } | ||
| 342 | |||
| 343 | #ifndef MODULE | ||
| 344 | static int __init arcrimi_setup(char *s) | ||
| 345 | { | ||
| 346 | int ints[8]; | ||
| 347 | s = get_options(s, 8, ints); | ||
| 348 | if (!ints[0]) | ||
| 349 | return 1; | ||
| 350 | switch (ints[0]) { | ||
| 351 | default: /* ERROR */ | ||
| 352 | printk("arcrimi: Too many arguments.\n"); | ||
| 353 | case 3: /* Node ID */ | ||
| 354 | node = ints[3]; | ||
| 355 | case 2: /* IRQ */ | ||
| 356 | irq = ints[2]; | ||
| 357 | case 1: /* IO address */ | ||
| 358 | io = ints[1]; | ||
| 359 | } | ||
| 360 | if (*s) | ||
| 361 | snprintf(device, sizeof(device), "%s", s); | ||
| 362 | return 1; | ||
| 363 | } | ||
| 364 | __setup("arcrimi=", arcrimi_setup); | ||
| 365 | #endif /* MODULE */ | ||
| 366 | |||
| 367 | module_init(arc_rimi_init) | ||
| 368 | module_exit(arc_rimi_exit) | ||
diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c new file mode 100644 index 00000000000..4f9f69e22c1 --- /dev/null +++ b/drivers/net/arcnet/arcnet.c | |||
| @@ -0,0 +1,1102 @@ | |||
| 1 | /* | ||
| 2 | * Linux ARCnet driver - device-independent routines | ||
| 3 | * | ||
| 4 | * Written 1997 by David Woodhouse. | ||
| 5 | * Written 1994-1999 by Avery Pennarun. | ||
| 6 | * Written 1999-2000 by Martin Mares <mj@ucw.cz>. | ||
| 7 | * Derived from skeleton.c by Donald Becker. | ||
| 8 | * | ||
| 9 | * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) | ||
| 10 | * for sponsoring the further development of this driver. | ||
| 11 | * | ||
| 12 | * ********************** | ||
| 13 | * | ||
| 14 | * The original copyright was as follows: | ||
| 15 | * | ||
| 16 | * skeleton.c Written 1993 by Donald Becker. | ||
| 17 | * Copyright 1993 United States Government as represented by the | ||
| 18 | * Director, National Security Agency. This software may only be used | ||
| 19 | * and distributed according to the terms of the GNU General Public License as | ||
| 20 | * modified by SRC, incorporated herein by reference. | ||
| 21 | * | ||
| 22 | * ********************** | ||
| 23 | * | ||
| 24 | * The change log is now in a file called ChangeLog in this directory. | ||
| 25 | * | ||
| 26 | * Sources: | ||
| 27 | * - Crynwr arcnet.com/arcether.com packet drivers. | ||
| 28 | * - arcnet.c v0.00 dated 1/1/94 and apparently by | ||
| 29 | * Donald Becker - it didn't work :) | ||
| 30 | * - skeleton.c v0.05 dated 11/16/93 by Donald Becker | ||
| 31 | * (from Linux Kernel 1.1.45) | ||
| 32 | * - RFC's 1201 and 1051 - re: TCP/IP over ARCnet | ||
| 33 | * - The official ARCnet COM9026 data sheets (!) thanks to | ||
| 34 | * Ken Cornetet <kcornete@nyx10.cs.du.edu> | ||
| 35 | * - The official ARCnet COM20020 data sheets. | ||
| 36 | * - Information on some more obscure ARCnet controller chips, thanks | ||
| 37 | * to the nice people at SMSC. | ||
| 38 | * - net/inet/eth.c (from kernel 1.1.50) for header-building info. | ||
| 39 | * - Alternate Linux ARCnet source by V.Shergin <vsher@sao.stavropol.su> | ||
| 40 | * - Textual information and more alternate source from Joachim Koenig | ||
| 41 | * <jojo@repas.de> | ||
| 42 | */ | ||
| 43 | |||
| 44 | #define VERSION "arcnet: v3.93 BETA 2000/04/29 - by Avery Pennarun et al.\n" | ||
| 45 | |||
| 46 | #include <linux/module.h> | ||
| 47 | #include <linux/config.h> | ||
| 48 | #include <linux/types.h> | ||
| 49 | #include <linux/delay.h> | ||
| 50 | #include <linux/netdevice.h> | ||
| 51 | #include <linux/if_arp.h> | ||
| 52 | #include <net/arp.h> | ||
| 53 | #include <linux/init.h> | ||
| 54 | #include <linux/arcdevice.h> | ||
| 55 | |||
| 56 | /* "do nothing" functions for protocol drivers */ | ||
| 57 | static void null_rx(struct net_device *dev, int bufnum, | ||
| 58 | struct archdr *pkthdr, int length); | ||
| 59 | static int null_build_header(struct sk_buff *skb, struct net_device *dev, | ||
| 60 | unsigned short type, uint8_t daddr); | ||
| 61 | static int null_prepare_tx(struct net_device *dev, struct archdr *pkt, | ||
| 62 | int length, int bufnum); | ||
| 63 | |||
| 64 | |||
| 65 | /* | ||
| 66 | * one ArcProto per possible proto ID. None of the elements of | ||
| 67 | * arc_proto_map are allowed to be NULL; they will get set to | ||
| 68 | * arc_proto_default instead. It also must not be NULL; if you would like | ||
| 69 | * to set it to NULL, set it to &arc_proto_null instead. | ||
| 70 | */ | ||
| 71 | struct ArcProto *arc_proto_map[256], *arc_proto_default, | ||
| 72 | *arc_bcast_proto, *arc_raw_proto; | ||
| 73 | |||
| 74 | struct ArcProto arc_proto_null = | ||
| 75 | { | ||
| 76 | .suffix = '?', | ||
| 77 | .mtu = XMTU, | ||
| 78 | .is_ip = 0, | ||
| 79 | .rx = null_rx, | ||
| 80 | .build_header = null_build_header, | ||
| 81 | .prepare_tx = null_prepare_tx, | ||
| 82 | .continue_tx = NULL, | ||
| 83 | .ack_tx = NULL | ||
| 84 | }; | ||
| 85 | |||
| 86 | /* Exported function prototypes */ | ||
| 87 | int arcnet_debug = ARCNET_DEBUG; | ||
| 88 | |||
| 89 | EXPORT_SYMBOL(arc_proto_map); | ||
| 90 | EXPORT_SYMBOL(arc_proto_default); | ||
| 91 | EXPORT_SYMBOL(arc_bcast_proto); | ||
| 92 | EXPORT_SYMBOL(arc_raw_proto); | ||
| 93 | EXPORT_SYMBOL(arc_proto_null); | ||
| 94 | EXPORT_SYMBOL(arcnet_unregister_proto); | ||
| 95 | EXPORT_SYMBOL(arcnet_debug); | ||
| 96 | EXPORT_SYMBOL(alloc_arcdev); | ||
| 97 | EXPORT_SYMBOL(arcnet_interrupt); | ||
| 98 | |||
| 99 | /* Internal function prototypes */ | ||
| 100 | static int arcnet_open(struct net_device *dev); | ||
| 101 | static int arcnet_close(struct net_device *dev); | ||
| 102 | static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev); | ||
| 103 | static void arcnet_timeout(struct net_device *dev); | ||
| 104 | static int arcnet_header(struct sk_buff *skb, struct net_device *dev, | ||
| 105 | unsigned short type, void *daddr, void *saddr, | ||
| 106 | unsigned len); | ||
| 107 | static int arcnet_rebuild_header(struct sk_buff *skb); | ||
| 108 | static struct net_device_stats *arcnet_get_stats(struct net_device *dev); | ||
| 109 | static int go_tx(struct net_device *dev); | ||
| 110 | |||
| 111 | static int debug = ARCNET_DEBUG; | ||
| 112 | module_param(debug, int, 0); | ||
| 113 | MODULE_LICENSE("GPL"); | ||
| 114 | |||
| 115 | static int __init arcnet_init(void) | ||
| 116 | { | ||
| 117 | int count; | ||
| 118 | |||
| 119 | arcnet_debug = debug; | ||
| 120 | |||
| 121 | printk(VERSION); | ||
| 122 | |||
| 123 | #ifdef ALPHA_WARNING | ||
| 124 | BUGLVL(D_EXTRA) { | ||
| 125 | printk("arcnet: ***\n" | ||
| 126 | "arcnet: * Read arcnet.txt for important release notes!\n" | ||
| 127 | "arcnet: *\n" | ||
| 128 | "arcnet: * This is an ALPHA version! (Last stable release: v3.02) E-mail\n" | ||
| 129 | "arcnet: * me if you have any questions, comments, or bug reports.\n" | ||
| 130 | "arcnet: ***\n"); | ||
| 131 | } | ||
| 132 | #endif | ||
| 133 | |||
| 134 | /* initialize the protocol map */ | ||
| 135 | arc_raw_proto = arc_proto_default = arc_bcast_proto = &arc_proto_null; | ||
| 136 | for (count = 0; count < 256; count++) | ||
| 137 | arc_proto_map[count] = arc_proto_default; | ||
| 138 | |||
| 139 | BUGLVL(D_DURING) | ||
| 140 | printk("arcnet: struct sizes: %Zd %Zd %Zd %Zd %Zd\n", | ||
| 141 | sizeof(struct arc_hardware), sizeof(struct arc_rfc1201), | ||
| 142 | sizeof(struct arc_rfc1051), sizeof(struct arc_eth_encap), | ||
| 143 | sizeof(struct archdr)); | ||
| 144 | |||
| 145 | return 0; | ||
| 146 | } | ||
| 147 | |||
| 148 | static void __exit arcnet_exit(void) | ||
| 149 | { | ||
| 150 | } | ||
| 151 | |||
| 152 | module_init(arcnet_init); | ||
| 153 | module_exit(arcnet_exit); | ||
| 154 | |||
| 155 | /* | ||
| 156 | * Dump the contents of an sk_buff | ||
| 157 | */ | ||
| 158 | #if ARCNET_DEBUG_MAX & D_SKB | ||
| 159 | void arcnet_dump_skb(struct net_device *dev, | ||
| 160 | struct sk_buff *skb, char *desc) | ||
| 161 | { | ||
| 162 | int i; | ||
| 163 | |||
| 164 | printk(KERN_DEBUG "%6s: skb dump (%s) follows:", dev->name, desc); | ||
| 165 | for (i = 0; i < skb->len; i++) { | ||
| 166 | if (i % 16 == 0) | ||
| 167 | printk("\n" KERN_DEBUG "[%04X] ", i); | ||
| 168 | printk("%02X ", ((u_char *) skb->data)[i]); | ||
| 169 | } | ||
| 170 | printk("\n"); | ||
| 171 | } | ||
| 172 | |||
| 173 | EXPORT_SYMBOL(arcnet_dump_skb); | ||
| 174 | #endif | ||
| 175 | |||
| 176 | |||
| 177 | /* | ||
| 178 | * Dump the contents of an ARCnet buffer | ||
| 179 | */ | ||
| 180 | #if (ARCNET_DEBUG_MAX & (D_RX | D_TX)) | ||
| 181 | void arcnet_dump_packet(struct net_device *dev, int bufnum, char *desc, | ||
| 182 | int take_arcnet_lock) | ||
| 183 | { | ||
| 184 | struct arcnet_local *lp = dev->priv; | ||
| 185 | int i, length; | ||
| 186 | unsigned long flags = 0; | ||
| 187 | static uint8_t buf[512]; | ||
| 188 | |||
| 189 | /* hw.copy_from_card expects IRQ context so take the IRQ lock | ||
| 190 | to keep it single threaded */ | ||
| 191 | if(take_arcnet_lock) | ||
| 192 | spin_lock_irqsave(&lp->lock, flags); | ||
| 193 | |||
| 194 | lp->hw.copy_from_card(dev, bufnum, 0, buf, 512); | ||
| 195 | if(take_arcnet_lock) | ||
| 196 | spin_unlock_irqrestore(&lp->lock, flags); | ||
| 197 | |||
| 198 | /* if the offset[0] byte is nonzero, this is a 256-byte packet */ | ||
| 199 | length = (buf[2] ? 256 : 512); | ||
| 200 | |||
| 201 | printk(KERN_DEBUG "%6s: packet dump (%s) follows:", dev->name, desc); | ||
| 202 | for (i = 0; i < length; i++) { | ||
| 203 | if (i % 16 == 0) | ||
| 204 | printk("\n" KERN_DEBUG "[%04X] ", i); | ||
| 205 | printk("%02X ", buf[i]); | ||
| 206 | } | ||
| 207 | printk("\n"); | ||
| 208 | |||
| 209 | } | ||
| 210 | |||
| 211 | EXPORT_SYMBOL(arcnet_dump_packet); | ||
| 212 | #endif | ||
| 213 | |||
| 214 | |||
| 215 | /* | ||
| 216 | * Unregister a protocol driver from the arc_proto_map. Protocol drivers | ||
| 217 | * are responsible for registering themselves, but the unregister routine | ||
| 218 | * is pretty generic so we'll do it here. | ||
| 219 | */ | ||
| 220 | void arcnet_unregister_proto(struct ArcProto *proto) | ||
| 221 | { | ||
| 222 | int count; | ||
| 223 | |||
| 224 | if (arc_proto_default == proto) | ||
| 225 | arc_proto_default = &arc_proto_null; | ||
| 226 | if (arc_bcast_proto == proto) | ||
| 227 | arc_bcast_proto = arc_proto_default; | ||
| 228 | if (arc_raw_proto == proto) | ||
| 229 | arc_raw_proto = arc_proto_default; | ||
| 230 | |||
| 231 | for (count = 0; count < 256; count++) { | ||
| 232 | if (arc_proto_map[count] == proto) | ||
| 233 | arc_proto_map[count] = arc_proto_default; | ||
| 234 | } | ||
| 235 | } | ||
| 236 | |||
| 237 | |||
| 238 | /* | ||
| 239 | * Add a buffer to the queue. Only the interrupt handler is allowed to do | ||
| 240 | * this, unless interrupts are disabled. | ||
| 241 | * | ||
| 242 | * Note: we don't check for a full queue, since there aren't enough buffers | ||
| 243 | * to more than fill it. | ||
| 244 | */ | ||
| 245 | static void release_arcbuf(struct net_device *dev, int bufnum) | ||
| 246 | { | ||
| 247 | struct arcnet_local *lp = dev->priv; | ||
| 248 | int i; | ||
| 249 | |||
| 250 | lp->buf_queue[lp->first_free_buf++] = bufnum; | ||
| 251 | lp->first_free_buf %= 5; | ||
| 252 | |||
| 253 | BUGLVL(D_DURING) { | ||
| 254 | BUGMSG(D_DURING, "release_arcbuf: freed #%d; buffer queue is now: ", | ||
| 255 | bufnum); | ||
| 256 | for (i = lp->next_buf; i != lp->first_free_buf; i = (i+1) % 5) | ||
| 257 | BUGMSG2(D_DURING, "#%d ", lp->buf_queue[i]); | ||
| 258 | BUGMSG2(D_DURING, "\n"); | ||
| 259 | } | ||
| 260 | } | ||
| 261 | |||
| 262 | |||
| 263 | /* | ||
| 264 | * Get a buffer from the queue. If this returns -1, there are no buffers | ||
| 265 | * available. | ||
| 266 | */ | ||
| 267 | static int get_arcbuf(struct net_device *dev) | ||
| 268 | { | ||
| 269 | struct arcnet_local *lp = dev->priv; | ||
| 270 | int buf = -1, i; | ||
| 271 | |||
| 272 | if (!atomic_dec_and_test(&lp->buf_lock)) { | ||
| 273 | /* already in this function */ | ||
| 274 | BUGMSG(D_NORMAL, "get_arcbuf: overlap (%d)!\n", | ||
| 275 | lp->buf_lock.counter); | ||
| 276 | } | ||
| 277 | else { /* we can continue */ | ||
| 278 | if (lp->next_buf >= 5) | ||
| 279 | lp->next_buf -= 5; | ||
| 280 | |||
| 281 | if (lp->next_buf == lp->first_free_buf) | ||
| 282 | BUGMSG(D_NORMAL, "get_arcbuf: BUG: no buffers are available??\n"); | ||
| 283 | else { | ||
| 284 | buf = lp->buf_queue[lp->next_buf++]; | ||
| 285 | lp->next_buf %= 5; | ||
| 286 | } | ||
| 287 | } | ||
| 288 | |||
| 289 | |||
| 290 | BUGLVL(D_DURING) { | ||
| 291 | BUGMSG(D_DURING, "get_arcbuf: got #%d; buffer queue is now: ", buf); | ||
| 292 | for (i = lp->next_buf; i != lp->first_free_buf; i = (i+1) % 5) | ||
| 293 | BUGMSG2(D_DURING, "#%d ", lp->buf_queue[i]); | ||
| 294 | BUGMSG2(D_DURING, "\n"); | ||
| 295 | } | ||
| 296 | |||
| 297 | atomic_inc(&lp->buf_lock); | ||
| 298 | return buf; | ||
| 299 | } | ||
| 300 | |||
| 301 | |||
| 302 | static int choose_mtu(void) | ||
| 303 | { | ||
| 304 | int count, mtu = 65535; | ||
| 305 | |||
| 306 | /* choose the smallest MTU of all available encaps */ | ||
| 307 | for (count = 0; count < 256; count++) { | ||
| 308 | if (arc_proto_map[count] != &arc_proto_null | ||
| 309 | && arc_proto_map[count]->mtu < mtu) { | ||
| 310 | mtu = arc_proto_map[count]->mtu; | ||
| 311 | } | ||
| 312 | } | ||
| 313 | |||
| 314 | return mtu == 65535 ? XMTU : mtu; | ||
| 315 | } | ||
| 316 | |||
| 317 | |||
| 318 | /* Setup a struct device for ARCnet. */ | ||
| 319 | static void arcdev_setup(struct net_device *dev) | ||
| 320 | { | ||
| 321 | dev->type = ARPHRD_ARCNET; | ||
| 322 | dev->hard_header_len = sizeof(struct archdr); | ||
| 323 | dev->mtu = choose_mtu(); | ||
| 324 | |||
| 325 | dev->addr_len = ARCNET_ALEN; | ||
| 326 | dev->tx_queue_len = 100; | ||
| 327 | dev->broadcast[0] = 0x00; /* for us, broadcasts are address 0 */ | ||
| 328 | dev->watchdog_timeo = TX_TIMEOUT; | ||
| 329 | |||
| 330 | /* New-style flags. */ | ||
| 331 | dev->flags = IFF_BROADCAST; | ||
| 332 | |||
| 333 | /* | ||
| 334 | * Put in this stuff here, so we don't have to export the symbols to | ||
| 335 | * the chipset drivers. | ||
| 336 | */ | ||
| 337 | dev->open = arcnet_open; | ||
| 338 | dev->stop = arcnet_close; | ||
| 339 | dev->hard_start_xmit = arcnet_send_packet; | ||
| 340 | dev->tx_timeout = arcnet_timeout; | ||
| 341 | dev->get_stats = arcnet_get_stats; | ||
| 342 | dev->hard_header = arcnet_header; | ||
| 343 | dev->rebuild_header = arcnet_rebuild_header; | ||
| 344 | } | ||
| 345 | |||
| 346 | struct net_device *alloc_arcdev(char *name) | ||
| 347 | { | ||
| 348 | struct net_device *dev; | ||
| 349 | |||
| 350 | dev = alloc_netdev(sizeof(struct arcnet_local), | ||
| 351 | name && *name ? name : "arc%d", arcdev_setup); | ||
| 352 | if(dev) { | ||
| 353 | struct arcnet_local *lp = (struct arcnet_local *) dev->priv; | ||
| 354 | spin_lock_init(&lp->lock); | ||
| 355 | } | ||
| 356 | |||
| 357 | return dev; | ||
| 358 | } | ||
| 359 | |||
| 360 | /* | ||
| 361 | * Open/initialize the board. This is called sometime after booting when | ||
| 362 | * the 'ifconfig' program is run. | ||
| 363 | * | ||
| 364 | * This routine should set everything up anew at each open, even registers | ||
| 365 | * that "should" only need to be set once at boot, so that there is | ||
| 366 | * non-reboot way to recover if something goes wrong. | ||
| 367 | */ | ||
| 368 | static int arcnet_open(struct net_device *dev) | ||
| 369 | { | ||
| 370 | struct arcnet_local *lp = dev->priv; | ||
| 371 | int count, newmtu, error; | ||
| 372 | |||
| 373 | BUGMSG(D_INIT,"opened."); | ||
| 374 | |||
| 375 | if (!try_module_get(lp->hw.owner)) | ||
| 376 | return -ENODEV; | ||
| 377 | |||
| 378 | BUGLVL(D_PROTO) { | ||
| 379 | int count; | ||
| 380 | BUGMSG(D_PROTO, "protocol map (default is '%c'): ", | ||
| 381 | arc_proto_default->suffix); | ||
| 382 | for (count = 0; count < 256; count++) | ||
| 383 | BUGMSG2(D_PROTO, "%c", arc_proto_map[count]->suffix); | ||
| 384 | BUGMSG2(D_PROTO, "\n"); | ||
| 385 | } | ||
| 386 | |||
| 387 | |||
| 388 | BUGMSG(D_INIT, "arcnet_open: resetting card.\n"); | ||
| 389 | |||
| 390 | /* try to put the card in a defined state - if it fails the first | ||
| 391 | * time, actually reset it. | ||
| 392 | */ | ||
| 393 | error = -ENODEV; | ||
| 394 | if (ARCRESET(0) && ARCRESET(1)) | ||
| 395 | goto out_module_put; | ||
| 396 | |||
| 397 | newmtu = choose_mtu(); | ||
| 398 | if (newmtu < dev->mtu) | ||
| 399 | dev->mtu = newmtu; | ||
| 400 | |||
| 401 | BUGMSG(D_INIT, "arcnet_open: mtu: %d.\n", dev->mtu); | ||
| 402 | |||
| 403 | /* autodetect the encapsulation for each host. */ | ||
| 404 | memset(lp->default_proto, 0, sizeof(lp->default_proto)); | ||
| 405 | |||
| 406 | /* the broadcast address is special - use the 'bcast' protocol */ | ||
| 407 | for (count = 0; count < 256; count++) { | ||
| 408 | if (arc_proto_map[count] == arc_bcast_proto) { | ||
| 409 | lp->default_proto[0] = count; | ||
| 410 | break; | ||
| 411 | } | ||
| 412 | } | ||
| 413 | |||
| 414 | /* initialize buffers */ | ||
| 415 | atomic_set(&lp->buf_lock, 1); | ||
| 416 | |||
| 417 | lp->next_buf = lp->first_free_buf = 0; | ||
| 418 | release_arcbuf(dev, 0); | ||
| 419 | release_arcbuf(dev, 1); | ||
| 420 | release_arcbuf(dev, 2); | ||
| 421 | release_arcbuf(dev, 3); | ||
| 422 | lp->cur_tx = lp->next_tx = -1; | ||
| 423 | lp->cur_rx = -1; | ||
| 424 | |||
| 425 | lp->rfc1201.sequence = 1; | ||
| 426 | |||
| 427 | /* bring up the hardware driver */ | ||
| 428 | if (lp->hw.open) | ||
| 429 | lp->hw.open(dev); | ||
| 430 | |||
| 431 | if (dev->dev_addr[0] == 0) | ||
| 432 | BUGMSG(D_NORMAL, "WARNING! Station address 00 is reserved " | ||
| 433 | "for broadcasts!\n"); | ||
| 434 | else if (dev->dev_addr[0] == 255) | ||
| 435 | BUGMSG(D_NORMAL, "WARNING! Station address FF may confuse " | ||
| 436 | "DOS networking programs!\n"); | ||
| 437 | |||
| 438 | BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); | ||
| 439 | if (ASTATUS() & RESETflag) { | ||
| 440 | BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); | ||
| 441 | ACOMMAND(CFLAGScmd | RESETclear); | ||
| 442 | } | ||
| 443 | |||
| 444 | |||
| 445 | BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); | ||
| 446 | /* make sure we're ready to receive IRQ's. */ | ||
| 447 | AINTMASK(0); | ||
| 448 | udelay(1); /* give it time to set the mask before | ||
| 449 | * we reset it again. (may not even be | ||
| 450 | * necessary) | ||
| 451 | */ | ||
| 452 | BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); | ||
| 453 | lp->intmask = NORXflag | RECONflag; | ||
| 454 | AINTMASK(lp->intmask); | ||
| 455 | BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); | ||
| 456 | |||
| 457 | netif_start_queue(dev); | ||
| 458 | |||
| 459 | return 0; | ||
| 460 | |||
| 461 | out_module_put: | ||
| 462 | module_put(lp->hw.owner); | ||
| 463 | return error; | ||
| 464 | } | ||
| 465 | |||
| 466 | |||
| 467 | /* The inverse routine to arcnet_open - shuts down the card. */ | ||
| 468 | static int arcnet_close(struct net_device *dev) | ||
| 469 | { | ||
| 470 | struct arcnet_local *lp = dev->priv; | ||
| 471 | |||
| 472 | netif_stop_queue(dev); | ||
| 473 | |||
| 474 | /* flush TX and disable RX */ | ||
| 475 | AINTMASK(0); | ||
| 476 | ACOMMAND(NOTXcmd); /* stop transmit */ | ||
| 477 | ACOMMAND(NORXcmd); /* disable receive */ | ||
| 478 | mdelay(1); | ||
| 479 | |||
| 480 | /* shut down the card */ | ||
| 481 | lp->hw.close(dev); | ||
| 482 | module_put(lp->hw.owner); | ||
| 483 | return 0; | ||
| 484 | } | ||
| 485 | |||
| 486 | |||
| 487 | static int arcnet_header(struct sk_buff *skb, struct net_device *dev, | ||
| 488 | unsigned short type, void *daddr, void *saddr, | ||
| 489 | unsigned len) | ||
| 490 | { | ||
| 491 | struct arcnet_local *lp = dev->priv; | ||
| 492 | uint8_t _daddr, proto_num; | ||
| 493 | struct ArcProto *proto; | ||
| 494 | |||
| 495 | BUGMSG(D_DURING, | ||
| 496 | "create header from %d to %d; protocol %d (%Xh); size %u.\n", | ||
| 497 | saddr ? *(uint8_t *) saddr : -1, | ||
| 498 | daddr ? *(uint8_t *) daddr : -1, | ||
| 499 | type, type, len); | ||
| 500 | |||
| 501 | if (skb->len!=0 && len != skb->len) | ||
| 502 | BUGMSG(D_NORMAL, "arcnet_header: Yikes! skb->len(%d) != len(%d)!\n", | ||
| 503 | skb->len, len); | ||
| 504 | |||
| 505 | |||
| 506 | /* Type is host order - ? */ | ||
| 507 | if(type == ETH_P_ARCNET) { | ||
| 508 | proto = arc_raw_proto; | ||
| 509 | BUGMSG(D_DEBUG, "arc_raw_proto used. proto='%c'\n",proto->suffix); | ||
| 510 | _daddr = daddr ? *(uint8_t *) daddr : 0; | ||
| 511 | } | ||
| 512 | else if (!daddr) { | ||
| 513 | /* | ||
| 514 | * if the dest addr isn't provided, we can't choose an encapsulation! | ||
| 515 | * Store the packet type (eg. ETH_P_IP) for now, and we'll push on a | ||
| 516 | * real header when we do rebuild_header. | ||
| 517 | */ | ||
| 518 | *(uint16_t *) skb_push(skb, 2) = type; | ||
| 519 | if (skb->nh.raw - skb->mac.raw != 2) | ||
| 520 | BUGMSG(D_NORMAL, "arcnet_header: Yikes! diff (%d) is not 2!\n", | ||
| 521 | (int)(skb->nh.raw - skb->mac.raw)); | ||
| 522 | return -2; /* return error -- can't transmit yet! */ | ||
| 523 | } | ||
| 524 | else { | ||
| 525 | /* otherwise, we can just add the header as usual. */ | ||
| 526 | _daddr = *(uint8_t *) daddr; | ||
| 527 | proto_num = lp->default_proto[_daddr]; | ||
| 528 | proto = arc_proto_map[proto_num]; | ||
| 529 | BUGMSG(D_DURING, "building header for %02Xh using protocol '%c'\n", | ||
| 530 | proto_num, proto->suffix); | ||
| 531 | if (proto == &arc_proto_null && arc_bcast_proto != proto) { | ||
| 532 | BUGMSG(D_DURING, "actually, let's use '%c' instead.\n", | ||
| 533 | arc_bcast_proto->suffix); | ||
| 534 | proto = arc_bcast_proto; | ||
| 535 | } | ||
| 536 | } | ||
| 537 | return proto->build_header(skb, dev, type, _daddr); | ||
| 538 | } | ||
| 539 | |||
| 540 | |||
| 541 | /* | ||
| 542 | * Rebuild the ARCnet hard header. This is called after an ARP (or in the | ||
| 543 | * future other address resolution) has completed on this sk_buff. We now | ||
| 544 | * let ARP fill in the destination field. | ||
| 545 | */ | ||
| 546 | static int arcnet_rebuild_header(struct sk_buff *skb) | ||
| 547 | { | ||
| 548 | struct net_device *dev = skb->dev; | ||
| 549 | struct arcnet_local *lp = dev->priv; | ||
| 550 | int status = 0; /* default is failure */ | ||
| 551 | unsigned short type; | ||
| 552 | uint8_t daddr=0; | ||
| 553 | struct ArcProto *proto; | ||
| 554 | |||
| 555 | if (skb->nh.raw - skb->mac.raw != 2) { | ||
| 556 | BUGMSG(D_NORMAL, | ||
| 557 | "rebuild_header: shouldn't be here! (hdrsize=%d)\n", | ||
| 558 | (int)(skb->nh.raw - skb->mac.raw)); | ||
| 559 | return 0; | ||
| 560 | } | ||
| 561 | type = *(uint16_t *) skb_pull(skb, 2); | ||
| 562 | BUGMSG(D_DURING, "rebuild header for protocol %Xh\n", type); | ||
| 563 | |||
| 564 | if (type == ETH_P_IP) { | ||
| 565 | #ifdef CONFIG_INET | ||
| 566 | BUGMSG(D_DURING, "rebuild header for ethernet protocol %Xh\n", type); | ||
| 567 | status = arp_find(&daddr, skb) ? 1 : 0; | ||
| 568 | BUGMSG(D_DURING, " rebuilt: dest is %d; protocol %Xh\n", | ||
| 569 | daddr, type); | ||
| 570 | #endif | ||
| 571 | } else { | ||
| 572 | BUGMSG(D_NORMAL, | ||
| 573 | "I don't understand ethernet protocol %Xh addresses!\n", type); | ||
| 574 | lp->stats.tx_errors++; | ||
| 575 | lp->stats.tx_aborted_errors++; | ||
| 576 | } | ||
| 577 | |||
| 578 | /* if we couldn't resolve the address... give up. */ | ||
| 579 | if (!status) | ||
| 580 | return 0; | ||
| 581 | |||
| 582 | /* add the _real_ header this time! */ | ||
| 583 | proto = arc_proto_map[lp->default_proto[daddr]]; | ||
| 584 | proto->build_header(skb, dev, type, daddr); | ||
| 585 | |||
| 586 | return 1; /* success */ | ||
| 587 | } | ||
| 588 | |||
| 589 | |||
| 590 | |||
| 591 | /* Called by the kernel in order to transmit a packet. */ | ||
| 592 | static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev) | ||
| 593 | { | ||
| 594 | struct arcnet_local *lp = dev->priv; | ||
| 595 | struct archdr *pkt; | ||
| 596 | struct arc_rfc1201 *soft; | ||
| 597 | struct ArcProto *proto; | ||
| 598 | int txbuf; | ||
| 599 | unsigned long flags; | ||
| 600 | int freeskb = 0; | ||
| 601 | |||
| 602 | BUGMSG(D_DURING, | ||
| 603 | "transmit requested (status=%Xh, txbufs=%d/%d, len=%d, protocol %x)\n", | ||
| 604 | ASTATUS(), lp->cur_tx, lp->next_tx, skb->len,skb->protocol); | ||
| 605 | |||
| 606 | pkt = (struct archdr *) skb->data; | ||
| 607 | soft = &pkt->soft.rfc1201; | ||
| 608 | proto = arc_proto_map[soft->proto]; | ||
| 609 | |||
| 610 | BUGMSG(D_SKB_SIZE, "skb: transmitting %d bytes to %02X\n", | ||
| 611 | skb->len, pkt->hard.dest); | ||
| 612 | BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "tx"); | ||
| 613 | |||
| 614 | /* fits in one packet? */ | ||
| 615 | if (skb->len - ARC_HDR_SIZE > XMTU && !proto->continue_tx) { | ||
| 616 | BUGMSG(D_NORMAL, "fixme: packet too large: compensating badly!\n"); | ||
| 617 | dev_kfree_skb(skb); | ||
| 618 | return 0; /* don't try again */ | ||
| 619 | } | ||
| 620 | |||
| 621 | /* We're busy transmitting a packet... */ | ||
| 622 | netif_stop_queue(dev); | ||
| 623 | |||
| 624 | spin_lock_irqsave(&lp->lock, flags); | ||
| 625 | AINTMASK(0); | ||
| 626 | |||
| 627 | txbuf = get_arcbuf(dev); | ||
| 628 | if (txbuf != -1) { | ||
| 629 | if (proto->prepare_tx(dev, pkt, skb->len, txbuf) && | ||
| 630 | !proto->ack_tx) { | ||
| 631 | /* done right away and we don't want to acknowledge | ||
| 632 | the package later - forget about it now */ | ||
| 633 | lp->stats.tx_bytes += skb->len; | ||
| 634 | freeskb = 1; | ||
| 635 | } else { | ||
| 636 | /* do it the 'split' way */ | ||
| 637 | lp->outgoing.proto = proto; | ||
| 638 | lp->outgoing.skb = skb; | ||
| 639 | lp->outgoing.pkt = pkt; | ||
| 640 | |||
| 641 | if (proto->continue_tx && | ||
| 642 | proto->continue_tx(dev, txbuf)) { | ||
| 643 | BUGMSG(D_NORMAL, | ||
| 644 | "bug! continue_tx finished the first time! " | ||
| 645 | "(proto='%c')\n", proto->suffix); | ||
| 646 | } | ||
| 647 | } | ||
| 648 | |||
| 649 | lp->next_tx = txbuf; | ||
| 650 | } else { | ||
| 651 | freeskb = 1; | ||
| 652 | } | ||
| 653 | |||
| 654 | BUGMSG(D_DEBUG, "%s: %d: %s, status: %x\n",__FILE__,__LINE__,__FUNCTION__,ASTATUS()); | ||
| 655 | /* make sure we didn't ignore a TX IRQ while we were in here */ | ||
| 656 | AINTMASK(0); | ||
| 657 | |||
| 658 | BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); | ||
| 659 | lp->intmask |= TXFREEflag|EXCNAKflag; | ||
| 660 | AINTMASK(lp->intmask); | ||
| 661 | BUGMSG(D_DEBUG, "%s: %d: %s, status: %x\n",__FILE__,__LINE__,__FUNCTION__,ASTATUS()); | ||
| 662 | |||
| 663 | spin_unlock_irqrestore(&lp->lock, flags); | ||
| 664 | if (freeskb) { | ||
| 665 | dev_kfree_skb(skb); | ||
| 666 | } | ||
| 667 | return 0; /* no need to try again */ | ||
| 668 | } | ||
| 669 | |||
| 670 | |||
| 671 | /* | ||
| 672 | * Actually start transmitting a packet that was loaded into a buffer | ||
| 673 | * by prepare_tx. This should _only_ be called by the interrupt handler. | ||
| 674 | */ | ||
| 675 | static int go_tx(struct net_device *dev) | ||
| 676 | { | ||
| 677 | struct arcnet_local *lp = dev->priv; | ||
| 678 | |||
| 679 | BUGMSG(D_DURING, "go_tx: status=%Xh, intmask=%Xh, next_tx=%d, cur_tx=%d\n", | ||
| 680 | ASTATUS(), lp->intmask, lp->next_tx, lp->cur_tx); | ||
| 681 | |||
| 682 | if (lp->cur_tx != -1 || lp->next_tx == -1) | ||
| 683 | return 0; | ||
| 684 | |||
| 685 | BUGLVL(D_TX) arcnet_dump_packet(dev, lp->next_tx, "go_tx", 0); | ||
| 686 | |||
| 687 | lp->cur_tx = lp->next_tx; | ||
| 688 | lp->next_tx = -1; | ||
| 689 | |||
| 690 | /* start sending */ | ||
| 691 | ACOMMAND(TXcmd | (lp->cur_tx << 3)); | ||
| 692 | |||
| 693 | dev->trans_start = jiffies; | ||
| 694 | lp->stats.tx_packets++; | ||
| 695 | lp->lasttrans_dest = lp->lastload_dest; | ||
| 696 | lp->lastload_dest = 0; | ||
| 697 | lp->excnak_pending = 0; | ||
| 698 | lp->intmask |= TXFREEflag|EXCNAKflag; | ||
| 699 | |||
| 700 | return 1; | ||
| 701 | } | ||
| 702 | |||
| 703 | |||
| 704 | /* Called by the kernel when transmit times out */ | ||
| 705 | static void arcnet_timeout(struct net_device *dev) | ||
| 706 | { | ||
| 707 | unsigned long flags; | ||
| 708 | struct arcnet_local *lp = dev->priv; | ||
| 709 | int status = ASTATUS(); | ||
| 710 | char *msg; | ||
| 711 | |||
| 712 | spin_lock_irqsave(&lp->lock, flags); | ||
| 713 | if (status & TXFREEflag) { /* transmit _DID_ finish */ | ||
| 714 | msg = " - missed IRQ?"; | ||
| 715 | } else { | ||
| 716 | msg = ""; | ||
| 717 | lp->stats.tx_aborted_errors++; | ||
| 718 | lp->timed_out = 1; | ||
| 719 | ACOMMAND(NOTXcmd | (lp->cur_tx << 3)); | ||
| 720 | } | ||
| 721 | lp->stats.tx_errors++; | ||
| 722 | |||
| 723 | /* make sure we didn't miss a TX or a EXC NAK IRQ */ | ||
| 724 | AINTMASK(0); | ||
| 725 | lp->intmask |= TXFREEflag|EXCNAKflag; | ||
| 726 | AINTMASK(lp->intmask); | ||
| 727 | |||
| 728 | spin_unlock_irqrestore(&lp->lock, flags); | ||
| 729 | |||
| 730 | if (jiffies - lp->last_timeout > 10*HZ) { | ||
| 731 | BUGMSG(D_EXTRA, "tx timed out%s (status=%Xh, intmask=%Xh, dest=%02Xh)\n", | ||
| 732 | msg, status, lp->intmask, lp->lasttrans_dest); | ||
| 733 | lp->last_timeout = jiffies; | ||
| 734 | } | ||
| 735 | |||
| 736 | if (lp->cur_tx == -1) | ||
| 737 | netif_wake_queue(dev); | ||
| 738 | } | ||
| 739 | |||
| 740 | |||
| 741 | /* | ||
| 742 | * The typical workload of the driver: Handle the network interface | ||
| 743 | * interrupts. Establish which device needs attention, and call the correct | ||
| 744 | * chipset interrupt handler. | ||
| 745 | */ | ||
| 746 | irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
| 747 | { | ||
| 748 | struct net_device *dev = dev_id; | ||
| 749 | struct arcnet_local *lp; | ||
| 750 | int recbuf, status, diagstatus, didsomething, boguscount; | ||
| 751 | int retval = IRQ_NONE; | ||
| 752 | |||
| 753 | BUGMSG(D_DURING, "\n"); | ||
| 754 | |||
| 755 | BUGMSG(D_DURING, "in arcnet_interrupt\n"); | ||
| 756 | |||
| 757 | lp = dev->priv; | ||
| 758 | if (!lp) | ||
| 759 | BUG(); | ||
| 760 | |||
| 761 | spin_lock(&lp->lock); | ||
| 762 | |||
| 763 | /* | ||
| 764 | * RESET flag was enabled - if device is not running, we must clear it right | ||
| 765 | * away (but nothing else). | ||
| 766 | */ | ||
| 767 | if (!netif_running(dev)) { | ||
| 768 | if (ASTATUS() & RESETflag) | ||
| 769 | ACOMMAND(CFLAGScmd | RESETclear); | ||
| 770 | AINTMASK(0); | ||
| 771 | spin_unlock(&lp->lock); | ||
| 772 | return IRQ_HANDLED; | ||
| 773 | } | ||
| 774 | |||
| 775 | BUGMSG(D_DURING, "in arcnet_inthandler (status=%Xh, intmask=%Xh)\n", | ||
| 776 | ASTATUS(), lp->intmask); | ||
| 777 | |||
| 778 | boguscount = 5; | ||
| 779 | do { | ||
| 780 | status = ASTATUS(); | ||
| 781 | diagstatus = (status >> 8) & 0xFF; | ||
| 782 | |||
| 783 | BUGMSG(D_DEBUG, "%s: %d: %s: status=%x\n", | ||
| 784 | __FILE__,__LINE__,__FUNCTION__,status); | ||
| 785 | didsomething = 0; | ||
| 786 | |||
| 787 | /* | ||
| 788 | * RESET flag was enabled - card is resetting and if RX is | ||
| 789 | * disabled, it's NOT because we just got a packet. | ||
| 790 | * | ||
| 791 | * The card is in an undefined state. Clear it out and start over. | ||
| 792 | */ | ||
| 793 | if (status & RESETflag) { | ||
| 794 | BUGMSG(D_NORMAL, "spurious reset (status=%Xh)\n", status); | ||
| 795 | arcnet_close(dev); | ||
| 796 | arcnet_open(dev); | ||
| 797 | |||
| 798 | /* get out of the interrupt handler! */ | ||
| 799 | break; | ||
| 800 | } | ||
| 801 | /* | ||
| 802 | * RX is inhibited - we must have received something. Prepare to | ||
| 803 | * receive into the next buffer. | ||
| 804 | * | ||
| 805 | * We don't actually copy the received packet from the card until | ||
| 806 | * after the transmit handler runs (and possibly launches the next | ||
| 807 | * tx); this should improve latency slightly if we get both types | ||
| 808 | * of interrupts at once. | ||
| 809 | */ | ||
| 810 | recbuf = -1; | ||
| 811 | if (status & lp->intmask & NORXflag) { | ||
| 812 | recbuf = lp->cur_rx; | ||
| 813 | BUGMSG(D_DURING, "Buffer #%d: receive irq (status=%Xh)\n", | ||
| 814 | recbuf, status); | ||
| 815 | |||
| 816 | lp->cur_rx = get_arcbuf(dev); | ||
| 817 | if (lp->cur_rx != -1) { | ||
| 818 | BUGMSG(D_DURING, "enabling receive to buffer #%d\n", | ||
| 819 | lp->cur_rx); | ||
| 820 | ACOMMAND(RXcmd | (lp->cur_rx << 3) | RXbcasts); | ||
| 821 | } | ||
| 822 | didsomething++; | ||
| 823 | } | ||
| 824 | |||
| 825 | if((diagstatus & EXCNAKflag)) { | ||
| 826 | BUGMSG(D_DURING, "EXCNAK IRQ (diagstat=%Xh)\n", | ||
| 827 | diagstatus); | ||
| 828 | |||
| 829 | ACOMMAND(NOTXcmd); /* disable transmit */ | ||
| 830 | lp->excnak_pending = 1; | ||
| 831 | |||
| 832 | ACOMMAND(EXCNAKclear); | ||
| 833 | lp->intmask &= ~(EXCNAKflag); | ||
| 834 | didsomething++; | ||
| 835 | } | ||
| 836 | |||
| 837 | |||
| 838 | /* a transmit finished, and we're interested in it. */ | ||
| 839 | if ((status & lp->intmask & TXFREEflag) || lp->timed_out) { | ||
| 840 | lp->intmask &= ~(TXFREEflag|EXCNAKflag); | ||
| 841 | |||
| 842 | BUGMSG(D_DURING, "TX IRQ (stat=%Xh)\n", status); | ||
| 843 | |||
| 844 | if (lp->cur_tx != -1 && !lp->timed_out) { | ||
| 845 | if(!(status & TXACKflag)) { | ||
| 846 | if (lp->lasttrans_dest != 0) { | ||
| 847 | BUGMSG(D_EXTRA, | ||
| 848 | "transmit was not acknowledged! " | ||
| 849 | "(status=%Xh, dest=%02Xh)\n", | ||
| 850 | status, lp->lasttrans_dest); | ||
| 851 | lp->stats.tx_errors++; | ||
| 852 | lp->stats.tx_carrier_errors++; | ||
| 853 | } else { | ||
| 854 | BUGMSG(D_DURING, | ||
| 855 | "broadcast was not acknowledged; that's normal " | ||
| 856 | "(status=%Xh, dest=%02Xh)\n", | ||
| 857 | status, lp->lasttrans_dest); | ||
| 858 | } | ||
| 859 | } | ||
| 860 | |||
| 861 | if (lp->outgoing.proto && | ||
| 862 | lp->outgoing.proto->ack_tx) { | ||
| 863 | int ackstatus; | ||
| 864 | if(status & TXACKflag) | ||
| 865 | ackstatus=2; | ||
| 866 | else if(lp->excnak_pending) | ||
| 867 | ackstatus=1; | ||
| 868 | else | ||
| 869 | ackstatus=0; | ||
| 870 | |||
| 871 | lp->outgoing.proto | ||
| 872 | ->ack_tx(dev, ackstatus); | ||
| 873 | } | ||
| 874 | } | ||
| 875 | if (lp->cur_tx != -1) | ||
| 876 | release_arcbuf(dev, lp->cur_tx); | ||
| 877 | |||
| 878 | lp->cur_tx = -1; | ||
| 879 | lp->timed_out = 0; | ||
| 880 | didsomething++; | ||
| 881 | |||
| 882 | /* send another packet if there is one */ | ||
| 883 | go_tx(dev); | ||
| 884 | |||
| 885 | /* continue a split packet, if any */ | ||
| 886 | if (lp->outgoing.proto && lp->outgoing.proto->continue_tx) { | ||
| 887 | int txbuf = get_arcbuf(dev); | ||
| 888 | if (txbuf != -1) { | ||
| 889 | if (lp->outgoing.proto->continue_tx(dev, txbuf)) { | ||
| 890 | /* that was the last segment */ | ||
| 891 | lp->stats.tx_bytes += lp->outgoing.skb->len; | ||
| 892 | if(!lp->outgoing.proto->ack_tx) | ||
| 893 | { | ||
| 894 | dev_kfree_skb_irq(lp->outgoing.skb); | ||
| 895 | lp->outgoing.proto = NULL; | ||
| 896 | } | ||
| 897 | } | ||
| 898 | lp->next_tx = txbuf; | ||
| 899 | } | ||
| 900 | } | ||
| 901 | /* inform upper layers of idleness, if necessary */ | ||
| 902 | if (lp->cur_tx == -1) | ||
| 903 | netif_wake_queue(dev); | ||
| 904 | } | ||
| 905 | /* now process the received packet, if any */ | ||
| 906 | if (recbuf != -1) { | ||
| 907 | BUGLVL(D_RX) arcnet_dump_packet(dev, recbuf, "rx irq", 0); | ||
| 908 | |||
| 909 | arcnet_rx(dev, recbuf); | ||
| 910 | release_arcbuf(dev, recbuf); | ||
| 911 | |||
| 912 | didsomething++; | ||
| 913 | } | ||
| 914 | if (status & lp->intmask & RECONflag) { | ||
| 915 | ACOMMAND(CFLAGScmd | CONFIGclear); | ||
| 916 | lp->stats.tx_carrier_errors++; | ||
| 917 | |||
| 918 | BUGMSG(D_RECON, "Network reconfiguration detected (status=%Xh)\n", | ||
| 919 | status); | ||
| 920 | |||
| 921 | /* is the RECON info empty or old? */ | ||
| 922 | if (!lp->first_recon || !lp->last_recon || | ||
| 923 | jiffies - lp->last_recon > HZ * 10) { | ||
| 924 | if (lp->network_down) | ||
| 925 | BUGMSG(D_NORMAL, "reconfiguration detected: cabling restored?\n"); | ||
| 926 | lp->first_recon = lp->last_recon = jiffies; | ||
| 927 | lp->num_recons = lp->network_down = 0; | ||
| 928 | |||
| 929 | BUGMSG(D_DURING, "recon: clearing counters.\n"); | ||
| 930 | } else { /* add to current RECON counter */ | ||
| 931 | lp->last_recon = jiffies; | ||
| 932 | lp->num_recons++; | ||
| 933 | |||
| 934 | BUGMSG(D_DURING, "recon: counter=%d, time=%lds, net=%d\n", | ||
| 935 | lp->num_recons, | ||
| 936 | (lp->last_recon - lp->first_recon) / HZ, | ||
| 937 | lp->network_down); | ||
| 938 | |||
| 939 | /* if network is marked up; | ||
| 940 | * and first_recon and last_recon are 60+ apart; | ||
| 941 | * and the average no. of recons counted is | ||
| 942 | * > RECON_THRESHOLD/min; | ||
| 943 | * then print a warning message. | ||
| 944 | */ | ||
| 945 | if (!lp->network_down | ||
| 946 | && (lp->last_recon - lp->first_recon) <= HZ * 60 | ||
| 947 | && lp->num_recons >= RECON_THRESHOLD) { | ||
| 948 | lp->network_down = 1; | ||
| 949 | BUGMSG(D_NORMAL, "many reconfigurations detected: cabling problem?\n"); | ||
| 950 | } else if (!lp->network_down | ||
| 951 | && lp->last_recon - lp->first_recon > HZ * 60) { | ||
| 952 | /* reset counters if we've gone for over a minute. */ | ||
| 953 | lp->first_recon = lp->last_recon; | ||
| 954 | lp->num_recons = 1; | ||
| 955 | } | ||
| 956 | } | ||
| 957 | } else if (lp->network_down && jiffies - lp->last_recon > HZ * 10) { | ||
| 958 | if (lp->network_down) | ||
| 959 | BUGMSG(D_NORMAL, "cabling restored?\n"); | ||
| 960 | lp->first_recon = lp->last_recon = 0; | ||
| 961 | lp->num_recons = lp->network_down = 0; | ||
| 962 | |||
| 963 | BUGMSG(D_DURING, "not recon: clearing counters anyway.\n"); | ||
| 964 | } | ||
| 965 | |||
| 966 | if(didsomething) { | ||
| 967 | retval |= IRQ_HANDLED; | ||
| 968 | } | ||
| 969 | } | ||
| 970 | while (--boguscount && didsomething); | ||
| 971 | |||
| 972 | BUGMSG(D_DURING, "arcnet_interrupt complete (status=%Xh, count=%d)\n", | ||
| 973 | ASTATUS(), boguscount); | ||
| 974 | BUGMSG(D_DURING, "\n"); | ||
| 975 | |||
| 976 | |||
| 977 | AINTMASK(0); | ||
| 978 | udelay(1); | ||
| 979 | AINTMASK(lp->intmask); | ||
| 980 | |||
| 981 | spin_unlock(&lp->lock); | ||
| 982 | return retval; | ||
| 983 | } | ||
| 984 | |||
| 985 | |||
| 986 | /* | ||
| 987 | * This is a generic packet receiver that calls arcnet??_rx depending on the | ||
| 988 | * protocol ID found. | ||
| 989 | */ | ||
| 990 | void arcnet_rx(struct net_device *dev, int bufnum) | ||
| 991 | { | ||
| 992 | struct arcnet_local *lp = dev->priv; | ||
| 993 | struct archdr pkt; | ||
| 994 | struct arc_rfc1201 *soft; | ||
| 995 | int length, ofs; | ||
| 996 | |||
| 997 | soft = &pkt.soft.rfc1201; | ||
| 998 | |||
| 999 | lp->hw.copy_from_card(dev, bufnum, 0, &pkt, sizeof(ARC_HDR_SIZE)); | ||
| 1000 | if (pkt.hard.offset[0]) { | ||
| 1001 | ofs = pkt.hard.offset[0]; | ||
| 1002 | length = 256 - ofs; | ||
| 1003 | } else { | ||
| 1004 | ofs = pkt.hard.offset[1]; | ||
| 1005 | length = 512 - ofs; | ||
| 1006 | } | ||
| 1007 | |||
| 1008 | /* get the full header, if possible */ | ||
| 1009 | if (sizeof(pkt.soft) <= length) | ||
| 1010 | lp->hw.copy_from_card(dev, bufnum, ofs, soft, sizeof(pkt.soft)); | ||
| 1011 | else { | ||
| 1012 | memset(&pkt.soft, 0, sizeof(pkt.soft)); | ||
| 1013 | lp->hw.copy_from_card(dev, bufnum, ofs, soft, length); | ||
| 1014 | } | ||
| 1015 | |||
| 1016 | BUGMSG(D_DURING, "Buffer #%d: received packet from %02Xh to %02Xh " | ||
| 1017 | "(%d+4 bytes)\n", | ||
| 1018 | bufnum, pkt.hard.source, pkt.hard.dest, length); | ||
| 1019 | |||
| 1020 | lp->stats.rx_packets++; | ||
| 1021 | lp->stats.rx_bytes += length + ARC_HDR_SIZE; | ||
| 1022 | |||
| 1023 | /* call the right receiver for the protocol */ | ||
| 1024 | if (arc_proto_map[soft->proto]->is_ip) { | ||
| 1025 | BUGLVL(D_PROTO) { | ||
| 1026 | struct ArcProto | ||
| 1027 | *oldp = arc_proto_map[lp->default_proto[pkt.hard.source]], | ||
| 1028 | *newp = arc_proto_map[soft->proto]; | ||
| 1029 | |||
| 1030 | if (oldp != newp) { | ||
| 1031 | BUGMSG(D_PROTO, | ||
| 1032 | "got protocol %02Xh; encap for host %02Xh is now '%c'" | ||
| 1033 | " (was '%c')\n", soft->proto, pkt.hard.source, | ||
| 1034 | newp->suffix, oldp->suffix); | ||
| 1035 | } | ||
| 1036 | } | ||
| 1037 | |||
| 1038 | /* broadcasts will always be done with the last-used encap. */ | ||
| 1039 | lp->default_proto[0] = soft->proto; | ||
| 1040 | |||
| 1041 | /* in striking contrast, the following isn't a hack. */ | ||
| 1042 | lp->default_proto[pkt.hard.source] = soft->proto; | ||
| 1043 | } | ||
| 1044 | /* call the protocol-specific receiver. */ | ||
| 1045 | arc_proto_map[soft->proto]->rx(dev, bufnum, &pkt, length); | ||
| 1046 | } | ||
| 1047 | |||
| 1048 | |||
| 1049 | |||
| 1050 | /* | ||
| 1051 | * Get the current statistics. This may be called with the card open or | ||
| 1052 | * closed. | ||
| 1053 | */ | ||
| 1054 | static struct net_device_stats *arcnet_get_stats(struct net_device *dev) | ||
| 1055 | { | ||
| 1056 | struct arcnet_local *lp = dev->priv; | ||
| 1057 | return &lp->stats; | ||
| 1058 | } | ||
| 1059 | |||
| 1060 | |||
| 1061 | static void null_rx(struct net_device *dev, int bufnum, | ||
| 1062 | struct archdr *pkthdr, int length) | ||
| 1063 | { | ||
| 1064 | BUGMSG(D_PROTO, | ||
| 1065 | "rx: don't know how to deal with proto %02Xh from host %02Xh.\n", | ||
| 1066 | pkthdr->soft.rfc1201.proto, pkthdr->hard.source); | ||
| 1067 | } | ||
| 1068 | |||
| 1069 | |||
| 1070 | static int null_build_header(struct sk_buff *skb, struct net_device *dev, | ||
| 1071 | unsigned short type, uint8_t daddr) | ||
| 1072 | { | ||
| 1073 | struct arcnet_local *lp = dev->priv; | ||
| 1074 | |||
| 1075 | BUGMSG(D_PROTO, | ||
| 1076 | "tx: can't build header for encap %02Xh; load a protocol driver.\n", | ||
| 1077 | lp->default_proto[daddr]); | ||
| 1078 | |||
| 1079 | /* always fails */ | ||
| 1080 | return 0; | ||
| 1081 | } | ||
| 1082 | |||
| 1083 | |||
| 1084 | /* the "do nothing" prepare_tx function warns that there's nothing to do. */ | ||
| 1085 | static int null_prepare_tx(struct net_device *dev, struct archdr *pkt, | ||
| 1086 | int length, int bufnum) | ||
| 1087 | { | ||
| 1088 | struct arcnet_local *lp = dev->priv; | ||
| 1089 | struct arc_hardware newpkt; | ||
| 1090 | |||
| 1091 | BUGMSG(D_PROTO, "tx: no encap for this host; load a protocol driver.\n"); | ||
| 1092 | |||
| 1093 | /* send a packet to myself -- will never get received, of course */ | ||
| 1094 | newpkt.source = newpkt.dest = dev->dev_addr[0]; | ||
| 1095 | |||
| 1096 | /* only one byte of actual data (and it's random) */ | ||
| 1097 | newpkt.offset[0] = 0xFF; | ||
| 1098 | |||
| 1099 | lp->hw.copy_to_card(dev, bufnum, 0, &newpkt, ARC_HDR_SIZE); | ||
| 1100 | |||
| 1101 | return 1; /* done */ | ||
| 1102 | } | ||
diff --git a/drivers/net/arcnet/capmode.c b/drivers/net/arcnet/capmode.c new file mode 100644 index 00000000000..16e155b0412 --- /dev/null +++ b/drivers/net/arcnet/capmode.c | |||
| @@ -0,0 +1,296 @@ | |||
| 1 | /* | ||
| 2 | * Linux ARCnet driver - "cap mode" packet encapsulation. | ||
| 3 | * It adds sequence numbers to packets for communicating between a user space | ||
| 4 | * application and the driver. After a transmit it sends a packet with protocol | ||
| 5 | * byte 0 back up to the userspace containing the sequence number of the packet | ||
| 6 | * plus the transmit-status on the ArcNet. | ||
| 7 | * | ||
| 8 | * Written 2002-4 by Esben Nielsen, Vestas Wind Systems A/S | ||
| 9 | * Derived from arc-rawmode.c by Avery Pennarun. | ||
| 10 | * arc-rawmode was in turned based on skeleton.c, see below. | ||
| 11 | * | ||
| 12 | * ********************** | ||
| 13 | * | ||
| 14 | * The original copyright of skeleton.c was as follows: | ||
| 15 | * | ||
| 16 | * skeleton.c Written 1993 by Donald Becker. | ||
| 17 | * Copyright 1993 United States Government as represented by the | ||
| 18 | * Director, National Security Agency. This software may only be used | ||
| 19 | * and distributed according to the terms of the GNU General Public License as | ||
| 20 | * modified by SRC, incorporated herein by reference. | ||
| 21 | * | ||
| 22 | * ********************** | ||
| 23 | * | ||
| 24 | * For more details, see drivers/net/arcnet.c | ||
| 25 | * | ||
| 26 | * ********************** | ||
| 27 | */ | ||
| 28 | |||
| 29 | #include <linux/module.h> | ||
| 30 | #include <linux/init.h> | ||
| 31 | #include <linux/if_arp.h> | ||
| 32 | #include <net/arp.h> | ||
| 33 | #include <linux/netdevice.h> | ||
| 34 | #include <linux/skbuff.h> | ||
| 35 | #include <linux/arcdevice.h> | ||
| 36 | |||
| 37 | #define VERSION "arcnet: cap mode (`c') encapsulation support loaded.\n" | ||
| 38 | |||
| 39 | |||
| 40 | static void rx(struct net_device *dev, int bufnum, | ||
| 41 | struct archdr *pkthdr, int length); | ||
| 42 | static int build_header(struct sk_buff *skb, | ||
| 43 | struct net_device *dev, | ||
| 44 | unsigned short type, | ||
| 45 | uint8_t daddr); | ||
| 46 | static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, | ||
| 47 | int bufnum); | ||
| 48 | static int ack_tx(struct net_device *dev, int acked); | ||
| 49 | |||
| 50 | |||
| 51 | struct ArcProto capmode_proto = | ||
| 52 | { | ||
| 53 | 'r', | ||
| 54 | XMTU, | ||
| 55 | 0, | ||
| 56 | rx, | ||
| 57 | build_header, | ||
| 58 | prepare_tx, | ||
| 59 | NULL, | ||
| 60 | ack_tx | ||
| 61 | }; | ||
| 62 | |||
| 63 | |||
| 64 | void arcnet_cap_init(void) | ||
| 65 | { | ||
| 66 | int count; | ||
| 67 | |||
| 68 | for (count = 1; count <= 8; count++) | ||
| 69 | if (arc_proto_map[count] == arc_proto_default) | ||
| 70 | arc_proto_map[count] = &capmode_proto; | ||
| 71 | |||
| 72 | /* for cap mode, we only set the bcast proto if there's no better one */ | ||
| 73 | if (arc_bcast_proto == arc_proto_default) | ||
| 74 | arc_bcast_proto = &capmode_proto; | ||
| 75 | |||
| 76 | arc_proto_default = &capmode_proto; | ||
| 77 | arc_raw_proto = &capmode_proto; | ||
| 78 | } | ||
| 79 | |||
| 80 | |||
| 81 | #ifdef MODULE | ||
| 82 | |||
| 83 | int __init init_module(void) | ||
| 84 | { | ||
| 85 | printk(VERSION); | ||
| 86 | arcnet_cap_init(); | ||
| 87 | return 0; | ||
| 88 | } | ||
| 89 | |||
| 90 | void cleanup_module(void) | ||
| 91 | { | ||
| 92 | arcnet_unregister_proto(&capmode_proto); | ||
| 93 | } | ||
| 94 | |||
| 95 | MODULE_LICENSE("GPL"); | ||
| 96 | #endif /* MODULE */ | ||
| 97 | |||
| 98 | |||
| 99 | |||
| 100 | /* packet receiver */ | ||
| 101 | static void rx(struct net_device *dev, int bufnum, | ||
| 102 | struct archdr *pkthdr, int length) | ||
| 103 | { | ||
| 104 | struct arcnet_local *lp = (struct arcnet_local *) dev->priv; | ||
| 105 | struct sk_buff *skb; | ||
| 106 | struct archdr *pkt = pkthdr; | ||
| 107 | char *pktbuf, *pkthdrbuf; | ||
| 108 | int ofs; | ||
| 109 | |||
| 110 | BUGMSG(D_DURING, "it's a raw(cap) packet (length=%d)\n", length); | ||
| 111 | |||
| 112 | if (length >= MinTU) | ||
| 113 | ofs = 512 - length; | ||
| 114 | else | ||
| 115 | ofs = 256 - length; | ||
| 116 | |||
| 117 | skb = alloc_skb(length + ARC_HDR_SIZE + sizeof(int), GFP_ATOMIC); | ||
| 118 | if (skb == NULL) { | ||
| 119 | BUGMSG(D_NORMAL, "Memory squeeze, dropping packet.\n"); | ||
| 120 | lp->stats.rx_dropped++; | ||
| 121 | return; | ||
| 122 | } | ||
| 123 | skb_put(skb, length + ARC_HDR_SIZE + sizeof(int)); | ||
| 124 | skb->dev = dev; | ||
| 125 | |||
| 126 | pkt = (struct archdr *) skb->data; | ||
| 127 | |||
| 128 | skb->mac.raw = skb->data; | ||
| 129 | skb_pull(skb, ARC_HDR_SIZE); | ||
| 130 | |||
| 131 | /* up to sizeof(pkt->soft) has already been copied from the card */ | ||
| 132 | /* squeeze in an int for the cap encapsulation */ | ||
| 133 | |||
| 134 | /* use these variables to be sure we count in bytes, not in | ||
| 135 | sizeof(struct archdr) */ | ||
| 136 | pktbuf=(char*)pkt; | ||
| 137 | pkthdrbuf=(char*)pkthdr; | ||
| 138 | memcpy(pktbuf, pkthdrbuf, ARC_HDR_SIZE+sizeof(pkt->soft.cap.proto)); | ||
| 139 | memcpy(pktbuf+ARC_HDR_SIZE+sizeof(pkt->soft.cap.proto)+sizeof(int), | ||
| 140 | pkthdrbuf+ARC_HDR_SIZE+sizeof(pkt->soft.cap.proto), | ||
| 141 | sizeof(struct archdr)-ARC_HDR_SIZE-sizeof(pkt->soft.cap.proto)); | ||
| 142 | |||
| 143 | if (length > sizeof(pkt->soft)) | ||
| 144 | lp->hw.copy_from_card(dev, bufnum, ofs + sizeof(pkt->soft), | ||
| 145 | pkt->soft.raw + sizeof(pkt->soft) | ||
| 146 | + sizeof(int), | ||
| 147 | length - sizeof(pkt->soft)); | ||
| 148 | |||
| 149 | BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx"); | ||
| 150 | |||
| 151 | skb->protocol = __constant_htons(ETH_P_ARCNET); | ||
| 152 | ; | ||
| 153 | netif_rx(skb); | ||
| 154 | dev->last_rx = jiffies; | ||
| 155 | } | ||
| 156 | |||
| 157 | |||
| 158 | /* | ||
| 159 | * Create the ARCnet hard/soft headers for cap mode. | ||
| 160 | * There aren't any soft headers in cap mode - not even the protocol id. | ||
| 161 | */ | ||
| 162 | static int build_header(struct sk_buff *skb, | ||
| 163 | struct net_device *dev, | ||
| 164 | unsigned short type, | ||
| 165 | uint8_t daddr) | ||
| 166 | { | ||
| 167 | int hdr_size = ARC_HDR_SIZE; | ||
| 168 | struct archdr *pkt = (struct archdr *) skb_push(skb, hdr_size); | ||
| 169 | |||
| 170 | BUGMSG(D_PROTO, "Preparing header for cap packet %x.\n", | ||
| 171 | *((int*)&pkt->soft.cap.cookie[0])); | ||
| 172 | /* | ||
| 173 | * Set the source hardware address. | ||
| 174 | * | ||
| 175 | * This is pretty pointless for most purposes, but it can help in | ||
| 176 | * debugging. ARCnet does not allow us to change the source address in | ||
| 177 | * the actual packet sent) | ||
| 178 | */ | ||
| 179 | pkt->hard.source = *dev->dev_addr; | ||
| 180 | |||
| 181 | /* see linux/net/ethernet/eth.c to see where I got the following */ | ||
| 182 | |||
| 183 | if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) { | ||
| 184 | /* | ||
| 185 | * FIXME: fill in the last byte of the dest ipaddr here to better | ||
| 186 | * comply with RFC1051 in "noarp" mode. | ||
| 187 | */ | ||
| 188 | pkt->hard.dest = 0; | ||
| 189 | return hdr_size; | ||
| 190 | } | ||
| 191 | /* otherwise, just fill it in and go! */ | ||
| 192 | pkt->hard.dest = daddr; | ||
| 193 | |||
| 194 | return hdr_size; /* success */ | ||
| 195 | } | ||
| 196 | |||
| 197 | |||
| 198 | static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, | ||
| 199 | int bufnum) | ||
| 200 | { | ||
| 201 | struct arcnet_local *lp = (struct arcnet_local *) dev->priv; | ||
| 202 | struct arc_hardware *hard = &pkt->hard; | ||
| 203 | int ofs; | ||
| 204 | |||
| 205 | |||
| 206 | /* hard header is not included in packet length */ | ||
| 207 | length -= ARC_HDR_SIZE; | ||
| 208 | /* And neither is the cookie field */ | ||
| 209 | length -= sizeof(int); | ||
| 210 | |||
| 211 | BUGMSG(D_DURING, "prepare_tx: txbufs=%d/%d/%d\n", | ||
| 212 | lp->next_tx, lp->cur_tx, bufnum); | ||
| 213 | |||
| 214 | BUGMSG(D_PROTO, "Sending for cap packet %x.\n", | ||
| 215 | *((int*)&pkt->soft.cap.cookie[0])); | ||
| 216 | |||
| 217 | if (length > XMTU) { | ||
| 218 | /* should never happen! other people already check for this. */ | ||
| 219 | BUGMSG(D_NORMAL, "Bug! prepare_tx with size %d (> %d)\n", | ||
| 220 | length, XMTU); | ||
| 221 | length = XMTU; | ||
| 222 | } | ||
| 223 | if (length > MinTU) { | ||
| 224 | hard->offset[0] = 0; | ||
| 225 | hard->offset[1] = ofs = 512 - length; | ||
| 226 | } else if (length > MTU) { | ||
| 227 | hard->offset[0] = 0; | ||
| 228 | hard->offset[1] = ofs = 512 - length - 3; | ||
| 229 | } else | ||
| 230 | hard->offset[0] = ofs = 256 - length; | ||
| 231 | |||
| 232 | BUGMSG(D_DURING, "prepare_tx: length=%d ofs=%d\n", | ||
| 233 | length,ofs); | ||
| 234 | |||
| 235 | // Copy the arcnet-header + the protocol byte down: | ||
| 236 | lp->hw.copy_to_card(dev, bufnum, 0, hard, ARC_HDR_SIZE); | ||
| 237 | lp->hw.copy_to_card(dev, bufnum, ofs, &pkt->soft.cap.proto, | ||
| 238 | sizeof(pkt->soft.cap.proto)); | ||
| 239 | |||
| 240 | // Skip the extra integer we have written into it as a cookie | ||
| 241 | // but write the rest of the message: | ||
| 242 | lp->hw.copy_to_card(dev, bufnum, ofs+1, | ||
| 243 | ((unsigned char*)&pkt->soft.cap.mes),length-1); | ||
| 244 | |||
| 245 | lp->lastload_dest = hard->dest; | ||
| 246 | |||
| 247 | return 1; /* done */ | ||
| 248 | } | ||
| 249 | |||
| 250 | |||
| 251 | static int ack_tx(struct net_device *dev, int acked) | ||
| 252 | { | ||
| 253 | struct arcnet_local *lp = (struct arcnet_local *) dev->priv; | ||
| 254 | struct sk_buff *ackskb; | ||
| 255 | struct archdr *ackpkt; | ||
| 256 | int length=sizeof(struct arc_cap); | ||
| 257 | |||
| 258 | BUGMSG(D_DURING, "capmode: ack_tx: protocol: %x: result: %d\n", | ||
| 259 | lp->outgoing.skb->protocol, acked); | ||
| 260 | |||
| 261 | BUGLVL(D_SKB) arcnet_dump_skb(dev, lp->outgoing.skb, "ack_tx"); | ||
| 262 | |||
| 263 | /* Now alloc a skb to send back up through the layers: */ | ||
| 264 | ackskb = alloc_skb(length + ARC_HDR_SIZE , GFP_ATOMIC); | ||
| 265 | if (ackskb == NULL) { | ||
| 266 | BUGMSG(D_NORMAL, "Memory squeeze, can't acknowledge.\n"); | ||
| 267 | goto free_outskb; | ||
| 268 | } | ||
| 269 | |||
| 270 | skb_put(ackskb, length + ARC_HDR_SIZE ); | ||
| 271 | ackskb->dev = dev; | ||
| 272 | |||
| 273 | ackpkt = (struct archdr *) ackskb->data; | ||
| 274 | |||
| 275 | ackskb->mac.raw = ackskb->data; | ||
| 276 | /* skb_pull(ackskb, ARC_HDR_SIZE); */ | ||
| 277 | |||
| 278 | |||
| 279 | memcpy(ackpkt, lp->outgoing.skb->data, ARC_HDR_SIZE+sizeof(struct arc_cap)); | ||
| 280 | ackpkt->soft.cap.proto=0; /* using protocol 0 for acknowledge */ | ||
| 281 | ackpkt->soft.cap.mes.ack=acked; | ||
| 282 | |||
| 283 | BUGMSG(D_PROTO, "Ackknowledge for cap packet %x.\n", | ||
| 284 | *((int*)&ackpkt->soft.cap.cookie[0])); | ||
| 285 | |||
| 286 | ackskb->protocol = __constant_htons(ETH_P_ARCNET); | ||
| 287 | |||
| 288 | BUGLVL(D_SKB) arcnet_dump_skb(dev, ackskb, "ack_tx_recv"); | ||
| 289 | netif_rx(ackskb); | ||
| 290 | |||
| 291 | free_outskb: | ||
| 292 | dev_kfree_skb_irq(lp->outgoing.skb); | ||
| 293 | lp->outgoing.proto = NULL; /* We are always finished when in this protocol */ | ||
| 294 | |||
| 295 | return 0; | ||
| 296 | } | ||
diff --git a/drivers/net/arcnet/com20020-isa.c b/drivers/net/arcnet/com20020-isa.c new file mode 100644 index 00000000000..9289e6103de --- /dev/null +++ b/drivers/net/arcnet/com20020-isa.c | |||
| @@ -0,0 +1,219 @@ | |||
| 1 | /* | ||
| 2 | * Linux ARCnet driver - COM20020 chipset support | ||
| 3 | * | ||
| 4 | * Written 1997 by David Woodhouse. | ||
| 5 | * Written 1994-1999 by Avery Pennarun. | ||
| 6 | * Written 1999-2000 by Martin Mares <mj@ucw.cz>. | ||
| 7 | * Derived from skeleton.c by Donald Becker. | ||
| 8 | * | ||
| 9 | * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) | ||
| 10 | * for sponsoring the further development of this driver. | ||
| 11 | * | ||
| 12 | * ********************** | ||
| 13 | * | ||
| 14 | * The original copyright of skeleton.c was as follows: | ||
| 15 | * | ||
| 16 | * skeleton.c Written 1993 by Donald Becker. | ||
| 17 | * Copyright 1993 United States Government as represented by the | ||
| 18 | * Director, National Security Agency. This software may only be used | ||
| 19 | * and distributed according to the terms of the GNU General Public License as | ||
| 20 | * modified by SRC, incorporated herein by reference. | ||
| 21 | * | ||
| 22 | * ********************** | ||
| 23 | * | ||
| 24 | * For more details, see drivers/net/arcnet.c | ||
| 25 | * | ||
| 26 | * ********************** | ||
| 27 | */ | ||
| 28 | #include <linux/module.h> | ||
| 29 | #include <linux/moduleparam.h> | ||
| 30 | #include <linux/kernel.h> | ||
| 31 | #include <linux/types.h> | ||
| 32 | #include <linux/ioport.h> | ||
| 33 | #include <linux/slab.h> | ||
| 34 | #include <linux/errno.h> | ||
| 35 | #include <linux/delay.h> | ||
| 36 | #include <linux/netdevice.h> | ||
| 37 | #include <linux/init.h> | ||
| 38 | #include <linux/bootmem.h> | ||
| 39 | #include <linux/arcdevice.h> | ||
| 40 | #include <linux/com20020.h> | ||
| 41 | |||
| 42 | #include <asm/io.h> | ||
| 43 | |||
| 44 | #define VERSION "arcnet: COM20020 ISA support (by David Woodhouse et al.)\n" | ||
| 45 | |||
| 46 | |||
| 47 | /* | ||
| 48 | * We cannot (yet) probe for an IO mapped card, although we can check that | ||
| 49 | * it's where we were told it was, and even do autoirq. | ||
| 50 | */ | ||
| 51 | static int __init com20020isa_probe(struct net_device *dev) | ||
| 52 | { | ||
| 53 | int ioaddr; | ||
| 54 | unsigned long airqmask; | ||
| 55 | struct arcnet_local *lp = dev->priv; | ||
| 56 | int err; | ||
| 57 | |||
| 58 | BUGLVL(D_NORMAL) printk(VERSION); | ||
| 59 | |||
| 60 | ioaddr = dev->base_addr; | ||
| 61 | if (!ioaddr) { | ||
| 62 | BUGMSG(D_NORMAL, "No autoprobe (yet) for IO mapped cards; you " | ||
| 63 | "must specify the base address!\n"); | ||
| 64 | return -ENODEV; | ||
| 65 | } | ||
| 66 | if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "arcnet (COM20020)")) { | ||
| 67 | BUGMSG(D_NORMAL, "IO region %xh-%xh already allocated.\n", | ||
| 68 | ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1); | ||
| 69 | return -ENXIO; | ||
| 70 | } | ||
| 71 | if (ASTATUS() == 0xFF) { | ||
| 72 | BUGMSG(D_NORMAL, "IO address %x empty\n", ioaddr); | ||
| 73 | err = -ENODEV; | ||
| 74 | goto out; | ||
| 75 | } | ||
| 76 | if (com20020_check(dev)) { | ||
| 77 | err = -ENODEV; | ||
| 78 | goto out; | ||
| 79 | } | ||
| 80 | |||
| 81 | if (!dev->irq) { | ||
| 82 | /* if we do this, we're sure to get an IRQ since the | ||
| 83 | * card has just reset and the NORXflag is on until | ||
| 84 | * we tell it to start receiving. | ||
| 85 | */ | ||
| 86 | BUGMSG(D_INIT_REASONS, "intmask was %02Xh\n", inb(_INTMASK)); | ||
| 87 | outb(0, _INTMASK); | ||
| 88 | airqmask = probe_irq_on(); | ||
| 89 | outb(NORXflag, _INTMASK); | ||
| 90 | udelay(1); | ||
| 91 | outb(0, _INTMASK); | ||
| 92 | dev->irq = probe_irq_off(airqmask); | ||
| 93 | |||
| 94 | if (dev->irq <= 0) { | ||
| 95 | BUGMSG(D_INIT_REASONS, "Autoprobe IRQ failed first time\n"); | ||
| 96 | airqmask = probe_irq_on(); | ||
| 97 | outb(NORXflag, _INTMASK); | ||
| 98 | udelay(5); | ||
| 99 | outb(0, _INTMASK); | ||
| 100 | dev->irq = probe_irq_off(airqmask); | ||
| 101 | if (dev->irq <= 0) { | ||
| 102 | BUGMSG(D_NORMAL, "Autoprobe IRQ failed.\n"); | ||
| 103 | err = -ENODEV; | ||
| 104 | goto out; | ||
| 105 | } | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | lp->card_name = "ISA COM20020"; | ||
| 110 | if ((err = com20020_found(dev, 0)) != 0) | ||
| 111 | goto out; | ||
| 112 | |||
| 113 | return 0; | ||
| 114 | |||
| 115 | out: | ||
| 116 | release_region(ioaddr, ARCNET_TOTAL_SIZE); | ||
| 117 | return err; | ||
| 118 | } | ||
| 119 | |||
| 120 | static int node = 0; | ||
| 121 | static int io = 0x0; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */ | ||
| 122 | static int irq = 0; /* or use the insmod io= irq= shmem= options */ | ||
| 123 | static char device[9]; /* use eg. device="arc1" to change name */ | ||
| 124 | static int timeout = 3; | ||
| 125 | static int backplane = 0; | ||
| 126 | static int clockp = 0; | ||
| 127 | static int clockm = 0; | ||
| 128 | |||
| 129 | module_param(node, int, 0); | ||
| 130 | module_param(io, int, 0); | ||
| 131 | module_param(irq, int, 0); | ||
| 132 | module_param_string(device, device, sizeof(device), 0); | ||
| 133 | module_param(timeout, int, 0); | ||
| 134 | module_param(backplane, int, 0); | ||
| 135 | module_param(clockp, int, 0); | ||
| 136 | module_param(clockm, int, 0); | ||
| 137 | |||
| 138 | MODULE_LICENSE("GPL"); | ||
| 139 | |||
| 140 | static struct net_device *my_dev; | ||
| 141 | |||
| 142 | static int __init com20020_init(void) | ||
| 143 | { | ||
| 144 | struct net_device *dev; | ||
| 145 | struct arcnet_local *lp; | ||
| 146 | |||
| 147 | dev = alloc_arcdev(device); | ||
| 148 | if (!dev) | ||
| 149 | return -ENOMEM; | ||
| 150 | |||
| 151 | if (node && node != 0xff) | ||
| 152 | dev->dev_addr[0] = node; | ||
| 153 | |||
| 154 | lp = dev->priv; | ||
| 155 | lp->backplane = backplane; | ||
| 156 | lp->clockp = clockp & 7; | ||
| 157 | lp->clockm = clockm & 3; | ||
| 158 | lp->timeout = timeout & 3; | ||
| 159 | lp->hw.owner = THIS_MODULE; | ||
| 160 | |||
| 161 | dev->base_addr = io; | ||
| 162 | dev->irq = irq; | ||
| 163 | |||
| 164 | if (dev->irq == 2) | ||
| 165 | dev->irq = 9; | ||
| 166 | |||
| 167 | if (com20020isa_probe(dev)) { | ||
| 168 | free_netdev(dev); | ||
| 169 | return -EIO; | ||
| 170 | } | ||
| 171 | |||
| 172 | my_dev = dev; | ||
| 173 | return 0; | ||
| 174 | } | ||
| 175 | |||
| 176 | static void __exit com20020_exit(void) | ||
| 177 | { | ||
| 178 | unregister_netdev(my_dev); | ||
| 179 | free_irq(my_dev->irq, my_dev); | ||
| 180 | release_region(my_dev->base_addr, ARCNET_TOTAL_SIZE); | ||
| 181 | free_netdev(my_dev); | ||
| 182 | } | ||
| 183 | |||
| 184 | #ifndef MODULE | ||
| 185 | static int __init com20020isa_setup(char *s) | ||
| 186 | { | ||
| 187 | int ints[8]; | ||
| 188 | |||
| 189 | s = get_options(s, 8, ints); | ||
| 190 | if (!ints[0]) | ||
| 191 | return 1; | ||
| 192 | |||
| 193 | switch (ints[0]) { | ||
| 194 | default: /* ERROR */ | ||
| 195 | printk("com90xx: Too many arguments.\n"); | ||
| 196 | case 6: /* Timeout */ | ||
| 197 | timeout = ints[6]; | ||
| 198 | case 5: /* CKP value */ | ||
| 199 | clockp = ints[5]; | ||
| 200 | case 4: /* Backplane flag */ | ||
| 201 | backplane = ints[4]; | ||
| 202 | case 3: /* Node ID */ | ||
| 203 | node = ints[3]; | ||
| 204 | case 2: /* IRQ */ | ||
| 205 | irq = ints[2]; | ||
| 206 | case 1: /* IO address */ | ||
| 207 | io = ints[1]; | ||
| 208 | } | ||
| 209 | if (*s) | ||
| 210 | snprintf(device, sizeof(device), "%s", s); | ||
| 211 | return 1; | ||
| 212 | } | ||
| 213 | |||
| 214 | __setup("com20020=", com20020isa_setup); | ||
| 215 | |||
| 216 | #endif /* MODULE */ | ||
| 217 | |||
| 218 | module_init(com20020_init) | ||
| 219 | module_exit(com20020_exit) | ||
diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c new file mode 100644 index 00000000000..96636ca8754 --- /dev/null +++ b/drivers/net/arcnet/com20020-pci.c | |||
| @@ -0,0 +1,189 @@ | |||
| 1 | /* | ||
| 2 | * Linux ARCnet driver - COM20020 PCI support | ||
| 3 | * Contemporary Controls PCI20 and SOHARD SH-ARC PCI | ||
| 4 | * | ||
| 5 | * Written 1994-1999 by Avery Pennarun, | ||
| 6 | * based on an ISA version by David Woodhouse. | ||
| 7 | * Written 1999-2000 by Martin Mares <mj@ucw.cz>. | ||
| 8 | * Derived from skeleton.c by Donald Becker. | ||
| 9 | * | ||
| 10 | * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) | ||
| 11 | * for sponsoring the further development of this driver. | ||
| 12 | * | ||
| 13 | * ********************** | ||
| 14 | * | ||
| 15 | * The original copyright of skeleton.c was as follows: | ||
| 16 | * | ||
| 17 | * skeleton.c Written 1993 by Donald Becker. | ||
| 18 | * Copyright 1993 United States Government as represented by the | ||
| 19 | * Director, National Security Agency. This software may only be used | ||
| 20 | * and distributed according to the terms of the GNU General Public License as | ||
| 21 | * modified by SRC, incorporated herein by reference. | ||
| 22 | * | ||
| 23 | * ********************** | ||
| 24 | * | ||
| 25 | * For more details, see drivers/net/arcnet.c | ||
| 26 | * | ||
| 27 | * ********************** | ||
| 28 | */ | ||
| 29 | #include <linux/module.h> | ||
| 30 | #include <linux/moduleparam.h> | ||
| 31 | #include <linux/kernel.h> | ||
| 32 | #include <linux/types.h> | ||
| 33 | #include <linux/ioport.h> | ||
| 34 | #include <linux/slab.h> | ||
| 35 | #include <linux/errno.h> | ||
| 36 | #include <linux/netdevice.h> | ||
| 37 | #include <linux/init.h> | ||
| 38 | #include <linux/pci.h> | ||
| 39 | #include <linux/arcdevice.h> | ||
| 40 | #include <linux/com20020.h> | ||
| 41 | |||
| 42 | #include <asm/io.h> | ||
| 43 | |||
| 44 | |||
| 45 | #define VERSION "arcnet: COM20020 PCI support\n" | ||
| 46 | |||
| 47 | /* Module parameters */ | ||
| 48 | |||
| 49 | static int node; | ||
| 50 | static char device[9]; /* use eg. device="arc1" to change name */ | ||
| 51 | static int timeout = 3; | ||
| 52 | static int backplane; | ||
| 53 | static int clockp; | ||
| 54 | static int clockm; | ||
| 55 | |||
| 56 | module_param(node, int, 0); | ||
| 57 | module_param_string(device, device, sizeof(device), 0); | ||
| 58 | module_param(timeout, int, 0); | ||
| 59 | module_param(backplane, int, 0); | ||
| 60 | module_param(clockp, int, 0); | ||
| 61 | module_param(clockm, int, 0); | ||
| 62 | MODULE_LICENSE("GPL"); | ||
| 63 | |||
| 64 | static int __devinit com20020pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | ||
| 65 | { | ||
| 66 | struct net_device *dev; | ||
| 67 | struct arcnet_local *lp; | ||
| 68 | int ioaddr, err; | ||
| 69 | |||
| 70 | if (pci_enable_device(pdev)) | ||
| 71 | return -EIO; | ||
| 72 | dev = alloc_arcdev(device); | ||
| 73 | if (!dev) | ||
| 74 | return -ENOMEM; | ||
| 75 | lp = dev->priv; | ||
| 76 | |||
| 77 | pci_set_drvdata(pdev, dev); | ||
| 78 | |||
| 79 | // SOHARD needs PCI base addr 4 | ||
| 80 | if (pdev->vendor==0x10B5) { | ||
| 81 | BUGMSG(D_NORMAL, "SOHARD\n"); | ||
| 82 | ioaddr = pci_resource_start(pdev, 4); | ||
| 83 | } | ||
| 84 | else { | ||
| 85 | BUGMSG(D_NORMAL, "Contemporary Controls\n"); | ||
| 86 | ioaddr = pci_resource_start(pdev, 2); | ||
| 87 | } | ||
| 88 | |||
| 89 | if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "com20020-pci")) { | ||
| 90 | BUGMSG(D_INIT, "IO region %xh-%xh already allocated.\n", | ||
| 91 | ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1); | ||
| 92 | err = -EBUSY; | ||
| 93 | goto out_dev; | ||
| 94 | } | ||
| 95 | |||
| 96 | // Dummy access after Reset | ||
| 97 | // ARCNET controller needs this access to detect bustype | ||
| 98 | outb(0x00,ioaddr+1); | ||
| 99 | inb(ioaddr+1); | ||
| 100 | |||
| 101 | dev->base_addr = ioaddr; | ||
| 102 | dev->irq = pdev->irq; | ||
| 103 | dev->dev_addr[0] = node; | ||
| 104 | lp->card_name = "PCI COM20020"; | ||
| 105 | lp->card_flags = id->driver_data; | ||
| 106 | lp->backplane = backplane; | ||
| 107 | lp->clockp = clockp & 7; | ||
| 108 | lp->clockm = clockm & 3; | ||
| 109 | lp->timeout = timeout; | ||
| 110 | lp->hw.owner = THIS_MODULE; | ||
| 111 | |||
| 112 | if (ASTATUS() == 0xFF) { | ||
| 113 | BUGMSG(D_NORMAL, "IO address %Xh was reported by PCI BIOS, " | ||
| 114 | "but seems empty!\n", ioaddr); | ||
| 115 | err = -EIO; | ||
| 116 | goto out_port; | ||
| 117 | } | ||
| 118 | if (com20020_check(dev)) { | ||
| 119 | err = -EIO; | ||
| 120 | goto out_port; | ||
| 121 | } | ||
| 122 | |||
| 123 | if ((err = com20020_found(dev, SA_SHIRQ)) != 0) | ||
| 124 | goto out_port; | ||
| 125 | |||
| 126 | return 0; | ||
| 127 | |||
| 128 | out_port: | ||
| 129 | release_region(ioaddr, ARCNET_TOTAL_SIZE); | ||
| 130 | out_dev: | ||
| 131 | free_netdev(dev); | ||
| 132 | return err; | ||
| 133 | } | ||
| 134 | |||
| 135 | static void __devexit com20020pci_remove(struct pci_dev *pdev) | ||
| 136 | { | ||
| 137 | struct net_device *dev = pci_get_drvdata(pdev); | ||
| 138 | unregister_netdev(dev); | ||
| 139 | free_irq(dev->irq, dev); | ||
| 140 | release_region(dev->base_addr, ARCNET_TOTAL_SIZE); | ||
| 141 | free_netdev(dev); | ||
| 142 | } | ||
| 143 | |||
| 144 | static struct pci_device_id com20020pci_id_table[] = { | ||
| 145 | { 0x1571, 0xa001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, | ||
| 146 | { 0x1571, 0xa002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, | ||
| 147 | { 0x1571, 0xa003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, | ||
| 148 | { 0x1571, 0xa004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, | ||
| 149 | { 0x1571, 0xa005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, | ||
| 150 | { 0x1571, 0xa006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, | ||
| 151 | { 0x1571, 0xa007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, | ||
| 152 | { 0x1571, 0xa008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, | ||
| 153 | { 0x1571, 0xa009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, | ||
| 154 | { 0x1571, 0xa00a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, | ||
| 155 | { 0x1571, 0xa00b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, | ||
| 156 | { 0x1571, 0xa00c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, | ||
| 157 | { 0x1571, 0xa00d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, | ||
| 158 | { 0x1571, 0xa201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, | ||
| 159 | { 0x1571, 0xa202, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, | ||
| 160 | { 0x1571, 0xa203, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, | ||
| 161 | { 0x1571, 0xa204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, | ||
| 162 | { 0x1571, 0xa205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, | ||
| 163 | { 0x1571, 0xa206, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, | ||
| 164 | { 0x10B5, 0x9050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, | ||
| 165 | {0,} | ||
| 166 | }; | ||
| 167 | |||
| 168 | MODULE_DEVICE_TABLE(pci, com20020pci_id_table); | ||
| 169 | |||
| 170 | static struct pci_driver com20020pci_driver = { | ||
| 171 | .name = "com20020", | ||
| 172 | .id_table = com20020pci_id_table, | ||
| 173 | .probe = com20020pci_probe, | ||
| 174 | .remove = __devexit_p(com20020pci_remove), | ||
| 175 | }; | ||
| 176 | |||
| 177 | static int __init com20020pci_init(void) | ||
| 178 | { | ||
| 179 | BUGLVL(D_NORMAL) printk(VERSION); | ||
| 180 | return pci_module_init(&com20020pci_driver); | ||
| 181 | } | ||
| 182 | |||
| 183 | static void __exit com20020pci_cleanup(void) | ||
| 184 | { | ||
| 185 | pci_unregister_driver(&com20020pci_driver); | ||
| 186 | } | ||
| 187 | |||
| 188 | module_init(com20020pci_init) | ||
| 189 | module_exit(com20020pci_cleanup) | ||
diff --git a/drivers/net/arcnet/com20020.c b/drivers/net/arcnet/com20020.c new file mode 100644 index 00000000000..0dc70c7b794 --- /dev/null +++ b/drivers/net/arcnet/com20020.c | |||
| @@ -0,0 +1,357 @@ | |||
| 1 | /* | ||
| 2 | * Linux ARCnet driver - COM20020 chipset support | ||
| 3 | * | ||
| 4 | * Written 1997 by David Woodhouse. | ||
| 5 | * Written 1994-1999 by Avery Pennarun. | ||
| 6 | * Written 1999 by Martin Mares <mj@ucw.cz>. | ||
| 7 | * Derived from skeleton.c by Donald Becker. | ||
| 8 | * | ||
| 9 | * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) | ||
| 10 | * for sponsoring the further development of this driver. | ||
| 11 | * | ||
| 12 | * ********************** | ||
| 13 | * | ||
| 14 | * The original copyright of skeleton.c was as follows: | ||
| 15 | * | ||
| 16 | * skeleton.c Written 1993 by Donald Becker. | ||
| 17 | * Copyright 1993 United States Government as represented by the | ||
| 18 | * Director, National Security Agency. This software may only be used | ||
| 19 | * and distributed according to the terms of the GNU General Public License as | ||
| 20 | * modified by SRC, incorporated herein by reference. | ||
| 21 | * | ||
| 22 | * ********************** | ||
| 23 | * | ||
| 24 | * For more details, see drivers/net/arcnet.c | ||
| 25 | * | ||
| 26 | * ********************** | ||
| 27 | */ | ||
| 28 | #include <linux/module.h> | ||
| 29 | #include <linux/kernel.h> | ||
| 30 | #include <linux/types.h> | ||
| 31 | #include <linux/ioport.h> | ||
| 32 | #include <linux/slab.h> | ||
| 33 | #include <linux/errno.h> | ||
| 34 | #include <linux/delay.h> | ||
| 35 | #include <linux/netdevice.h> | ||
| 36 | #include <linux/init.h> | ||
| 37 | #include <linux/arcdevice.h> | ||
| 38 | #include <linux/com20020.h> | ||
| 39 | |||
| 40 | #include <asm/io.h> | ||
| 41 | |||
| 42 | #define VERSION "arcnet: COM20020 chipset support (by David Woodhouse et al.)\n" | ||
| 43 | |||
| 44 | static char *clockrates[] = | ||
| 45 | {"10 Mb/s", "Reserved", "5 Mb/s", | ||
| 46 | "2.5 Mb/s", "1.25Mb/s", "625 Kb/s", "312.5 Kb/s", | ||
| 47 | "156.25 Kb/s", "Reserved", "Reserved", "Reserved"}; | ||
| 48 | |||
| 49 | static void com20020_command(struct net_device *dev, int command); | ||
| 50 | static int com20020_status(struct net_device *dev); | ||
| 51 | static void com20020_setmask(struct net_device *dev, int mask); | ||
| 52 | static int com20020_reset(struct net_device *dev, int really_reset); | ||
| 53 | static void com20020_copy_to_card(struct net_device *dev, int bufnum, | ||
| 54 | int offset, void *buf, int count); | ||
| 55 | static void com20020_copy_from_card(struct net_device *dev, int bufnum, | ||
| 56 | int offset, void *buf, int count); | ||
| 57 | static void com20020_set_mc_list(struct net_device *dev); | ||
| 58 | static void com20020_close(struct net_device *); | ||
| 59 | |||
| 60 | static void com20020_copy_from_card(struct net_device *dev, int bufnum, | ||
| 61 | int offset, void *buf, int count) | ||
| 62 | { | ||
| 63 | int ioaddr = dev->base_addr, ofs = 512 * bufnum + offset; | ||
| 64 | |||
| 65 | /* set up the address register */ | ||
| 66 | outb((ofs >> 8) | RDDATAflag | AUTOINCflag, _ADDR_HI); | ||
| 67 | outb(ofs & 0xff, _ADDR_LO); | ||
| 68 | |||
| 69 | /* copy the data */ | ||
| 70 | TIME("insb", count, insb(_MEMDATA, buf, count)); | ||
| 71 | } | ||
| 72 | |||
| 73 | |||
| 74 | static void com20020_copy_to_card(struct net_device *dev, int bufnum, | ||
| 75 | int offset, void *buf, int count) | ||
| 76 | { | ||
| 77 | int ioaddr = dev->base_addr, ofs = 512 * bufnum + offset; | ||
| 78 | |||
| 79 | /* set up the address register */ | ||
| 80 | outb((ofs >> 8) | AUTOINCflag, _ADDR_HI); | ||
| 81 | outb(ofs & 0xff, _ADDR_LO); | ||
| 82 | |||
| 83 | /* copy the data */ | ||
| 84 | TIME("outsb", count, outsb(_MEMDATA, buf, count)); | ||
| 85 | } | ||
| 86 | |||
| 87 | |||
| 88 | /* Reset the card and check some basic stuff during the detection stage. */ | ||
| 89 | int com20020_check(struct net_device *dev) | ||
| 90 | { | ||
| 91 | int ioaddr = dev->base_addr, status; | ||
| 92 | struct arcnet_local *lp = dev->priv; | ||
| 93 | |||
| 94 | ARCRESET0; | ||
| 95 | mdelay(RESETtime); | ||
| 96 | |||
| 97 | lp->setup = lp->clockm ? 0 : (lp->clockp << 1); | ||
| 98 | lp->setup2 = (lp->clockm << 4) | 8; | ||
| 99 | |||
| 100 | /* CHECK: should we do this for SOHARD cards ? */ | ||
| 101 | /* Enable P1Mode for backplane mode */ | ||
| 102 | lp->setup = lp->setup | P1MODE; | ||
| 103 | |||
| 104 | SET_SUBADR(SUB_SETUP1); | ||
| 105 | outb(lp->setup, _XREG); | ||
| 106 | |||
| 107 | if (lp->card_flags & ARC_CAN_10MBIT) | ||
| 108 | { | ||
| 109 | SET_SUBADR(SUB_SETUP2); | ||
| 110 | outb(lp->setup2, _XREG); | ||
| 111 | |||
| 112 | /* must now write the magic "restart operation" command */ | ||
| 113 | mdelay(1); | ||
| 114 | outb(0x18, _COMMAND); | ||
| 115 | } | ||
| 116 | |||
| 117 | lp->config = 0x21 | (lp->timeout << 3) | (lp->backplane << 2); | ||
| 118 | /* set node ID to 0x42 (but transmitter is disabled, so it's okay) */ | ||
| 119 | SETCONF; | ||
| 120 | outb(0x42, ioaddr + BUS_ALIGN*7); | ||
| 121 | |||
| 122 | status = ASTATUS(); | ||
| 123 | |||
| 124 | if ((status & 0x99) != (NORXflag | TXFREEflag | RESETflag)) { | ||
| 125 | BUGMSG(D_NORMAL, "status invalid (%Xh).\n", status); | ||
| 126 | return -ENODEV; | ||
| 127 | } | ||
| 128 | BUGMSG(D_INIT_REASONS, "status after reset: %X\n", status); | ||
| 129 | |||
| 130 | /* Enable TX */ | ||
| 131 | outb(0x39, _CONFIG); | ||
| 132 | outb(inb(ioaddr + BUS_ALIGN*8), ioaddr + BUS_ALIGN*7); | ||
| 133 | |||
| 134 | ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear); | ||
| 135 | |||
| 136 | status = ASTATUS(); | ||
| 137 | BUGMSG(D_INIT_REASONS, "status after reset acknowledged: %X\n", | ||
| 138 | status); | ||
| 139 | |||
| 140 | /* Read first location of memory */ | ||
| 141 | outb(0 | RDDATAflag | AUTOINCflag, _ADDR_HI); | ||
| 142 | outb(0, _ADDR_LO); | ||
| 143 | |||
| 144 | if ((status = inb(_MEMDATA)) != TESTvalue) { | ||
| 145 | BUGMSG(D_NORMAL, "Signature byte not found (%02Xh != D1h).\n", | ||
| 146 | status); | ||
| 147 | return -ENODEV; | ||
| 148 | } | ||
| 149 | return 0; | ||
| 150 | } | ||
| 151 | |||
| 152 | /* Set up the struct net_device associated with this card. Called after | ||
| 153 | * probing succeeds. | ||
| 154 | */ | ||
| 155 | int com20020_found(struct net_device *dev, int shared) | ||
| 156 | { | ||
| 157 | struct arcnet_local *lp; | ||
| 158 | int ioaddr = dev->base_addr; | ||
| 159 | |||
| 160 | /* Initialize the rest of the device structure. */ | ||
| 161 | |||
| 162 | lp = dev->priv; | ||
| 163 | |||
| 164 | lp->hw.owner = THIS_MODULE; | ||
| 165 | lp->hw.command = com20020_command; | ||
| 166 | lp->hw.status = com20020_status; | ||
| 167 | lp->hw.intmask = com20020_setmask; | ||
| 168 | lp->hw.reset = com20020_reset; | ||
| 169 | lp->hw.copy_to_card = com20020_copy_to_card; | ||
| 170 | lp->hw.copy_from_card = com20020_copy_from_card; | ||
| 171 | lp->hw.close = com20020_close; | ||
| 172 | |||
| 173 | dev->set_multicast_list = com20020_set_mc_list; | ||
| 174 | |||
| 175 | if (!dev->dev_addr[0]) | ||
| 176 | dev->dev_addr[0] = inb(ioaddr + BUS_ALIGN*8); /* FIXME: do this some other way! */ | ||
| 177 | |||
| 178 | SET_SUBADR(SUB_SETUP1); | ||
| 179 | outb(lp->setup, _XREG); | ||
| 180 | |||
| 181 | if (lp->card_flags & ARC_CAN_10MBIT) | ||
| 182 | { | ||
| 183 | SET_SUBADR(SUB_SETUP2); | ||
| 184 | outb(lp->setup2, _XREG); | ||
| 185 | |||
| 186 | /* must now write the magic "restart operation" command */ | ||
| 187 | mdelay(1); | ||
| 188 | outb(0x18, _COMMAND); | ||
| 189 | } | ||
| 190 | |||
| 191 | lp->config = 0x20 | (lp->timeout << 3) | (lp->backplane << 2) | 1; | ||
| 192 | /* Default 0x38 + register: Node ID */ | ||
| 193 | SETCONF; | ||
| 194 | outb(dev->dev_addr[0], _XREG); | ||
| 195 | |||
| 196 | /* reserve the irq */ | ||
| 197 | if (request_irq(dev->irq, &arcnet_interrupt, shared, | ||
| 198 | "arcnet (COM20020)", dev)) { | ||
| 199 | BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq); | ||
| 200 | return -ENODEV; | ||
| 201 | } | ||
| 202 | |||
| 203 | dev->base_addr = ioaddr; | ||
| 204 | |||
| 205 | BUGMSG(D_NORMAL, "%s: station %02Xh found at %03lXh, IRQ %d.\n", | ||
| 206 | lp->card_name, dev->dev_addr[0], dev->base_addr, dev->irq); | ||
| 207 | |||
| 208 | if (lp->backplane) | ||
| 209 | BUGMSG(D_NORMAL, "Using backplane mode.\n"); | ||
| 210 | |||
| 211 | if (lp->timeout != 3) | ||
| 212 | BUGMSG(D_NORMAL, "Using extended timeout value of %d.\n", lp->timeout); | ||
| 213 | |||
| 214 | BUGMSG(D_NORMAL, "Using CKP %d - data rate %s.\n", | ||
| 215 | lp->setup >> 1, | ||
| 216 | clockrates[3 - ((lp->setup2 & 0xF0) >> 4) + ((lp->setup & 0x0F) >> 1)]); | ||
| 217 | |||
| 218 | if (register_netdev(dev)) { | ||
| 219 | free_irq(dev->irq, dev); | ||
| 220 | return -EIO; | ||
| 221 | } | ||
| 222 | return 0; | ||
| 223 | } | ||
| 224 | |||
| 225 | |||
| 226 | /* | ||
| 227 | * Do a hardware reset on the card, and set up necessary registers. | ||
| 228 | * | ||
| 229 | * This should be called as little as possible, because it disrupts the | ||
| 230 | * token on the network (causes a RECON) and requires a significant delay. | ||
| 231 | * | ||
| 232 | * However, it does make sure the card is in a defined state. | ||
| 233 | */ | ||
| 234 | static int com20020_reset(struct net_device *dev, int really_reset) | ||
| 235 | { | ||
| 236 | struct arcnet_local *lp = dev->priv; | ||
| 237 | u_int ioaddr = dev->base_addr; | ||
| 238 | u_char inbyte; | ||
| 239 | |||
| 240 | BUGMSG(D_DEBUG, "%s: %d: %s: dev: %p, lp: %p, dev->name: %s\n", | ||
| 241 | __FILE__,__LINE__,__FUNCTION__,dev,lp,dev->name); | ||
| 242 | BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n", | ||
| 243 | dev->name, ASTATUS()); | ||
| 244 | |||
| 245 | BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); | ||
| 246 | lp->config = TXENcfg | (lp->timeout << 3) | (lp->backplane << 2); | ||
| 247 | /* power-up defaults */ | ||
| 248 | SETCONF; | ||
| 249 | BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); | ||
| 250 | |||
| 251 | if (really_reset) { | ||
| 252 | /* reset the card */ | ||
| 253 | ARCRESET; | ||
| 254 | mdelay(RESETtime * 2); /* COM20020 seems to be slower sometimes */ | ||
| 255 | } | ||
| 256 | /* clear flags & end reset */ | ||
| 257 | BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); | ||
| 258 | ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear); | ||
| 259 | |||
| 260 | /* verify that the ARCnet signature byte is present */ | ||
| 261 | BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); | ||
| 262 | |||
| 263 | com20020_copy_from_card(dev, 0, 0, &inbyte, 1); | ||
| 264 | BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); | ||
| 265 | if (inbyte != TESTvalue) { | ||
| 266 | BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); | ||
| 267 | BUGMSG(D_NORMAL, "reset failed: TESTvalue not present.\n"); | ||
| 268 | return 1; | ||
| 269 | } | ||
| 270 | /* enable extended (512-byte) packets */ | ||
| 271 | ACOMMAND(CONFIGcmd | EXTconf); | ||
| 272 | BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__); | ||
| 273 | |||
| 274 | /* done! return success. */ | ||
| 275 | return 0; | ||
| 276 | } | ||
| 277 | |||
| 278 | |||
| 279 | static void com20020_setmask(struct net_device *dev, int mask) | ||
| 280 | { | ||
| 281 | u_int ioaddr = dev->base_addr; | ||
| 282 | BUGMSG(D_DURING, "Setting mask to %x at %x\n",mask,ioaddr); | ||
| 283 | AINTMASK(mask); | ||
| 284 | } | ||
| 285 | |||
| 286 | |||
| 287 | static void com20020_command(struct net_device *dev, int cmd) | ||
| 288 | { | ||
| 289 | u_int ioaddr = dev->base_addr; | ||
| 290 | ACOMMAND(cmd); | ||
| 291 | } | ||
| 292 | |||
| 293 | |||
| 294 | static int com20020_status(struct net_device *dev) | ||
| 295 | { | ||
| 296 | u_int ioaddr = dev->base_addr; | ||
| 297 | |||
| 298 | return ASTATUS() + (ADIAGSTATUS()<<8); | ||
| 299 | } | ||
| 300 | |||
| 301 | static void com20020_close(struct net_device *dev) | ||
| 302 | { | ||
| 303 | struct arcnet_local *lp = dev->priv; | ||
| 304 | int ioaddr = dev->base_addr; | ||
| 305 | |||
| 306 | /* disable transmitter */ | ||
| 307 | lp->config &= ~TXENcfg; | ||
| 308 | SETCONF; | ||
| 309 | } | ||
| 310 | |||
| 311 | /* Set or clear the multicast filter for this adaptor. | ||
| 312 | * num_addrs == -1 Promiscuous mode, receive all packets | ||
| 313 | * num_addrs == 0 Normal mode, clear multicast list | ||
| 314 | * num_addrs > 0 Multicast mode, receive normal and MC packets, and do | ||
| 315 | * best-effort filtering. | ||
| 316 | * FIXME - do multicast stuff, not just promiscuous. | ||
| 317 | */ | ||
| 318 | static void com20020_set_mc_list(struct net_device *dev) | ||
| 319 | { | ||
| 320 | struct arcnet_local *lp = dev->priv; | ||
| 321 | int ioaddr = dev->base_addr; | ||
| 322 | |||
| 323 | if ((dev->flags & IFF_PROMISC) && (dev->flags & IFF_UP)) { /* Enable promiscuous mode */ | ||
| 324 | if (!(lp->setup & PROMISCset)) | ||
| 325 | BUGMSG(D_NORMAL, "Setting promiscuous flag...\n"); | ||
| 326 | SET_SUBADR(SUB_SETUP1); | ||
| 327 | lp->setup |= PROMISCset; | ||
| 328 | outb(lp->setup, _XREG); | ||
| 329 | } else | ||
| 330 | /* Disable promiscuous mode, use normal mode */ | ||
| 331 | { | ||
| 332 | if ((lp->setup & PROMISCset)) | ||
| 333 | BUGMSG(D_NORMAL, "Resetting promiscuous flag...\n"); | ||
| 334 | SET_SUBADR(SUB_SETUP1); | ||
| 335 | lp->setup &= ~PROMISCset; | ||
| 336 | outb(lp->setup, _XREG); | ||
| 337 | } | ||
| 338 | } | ||
| 339 | |||
| 340 | #ifdef MODULE | ||
| 341 | |||
| 342 | EXPORT_SYMBOL(com20020_check); | ||
| 343 | EXPORT_SYMBOL(com20020_found); | ||
| 344 | |||
| 345 | MODULE_LICENSE("GPL"); | ||
| 346 | |||
| 347 | int init_module(void) | ||
| 348 | { | ||
| 349 | BUGLVL(D_NORMAL) printk(VERSION); | ||
| 350 | return 0; | ||
| 351 | } | ||
| 352 | |||
| 353 | void cleanup_module(void) | ||
| 354 | { | ||
| 355 | } | ||
| 356 | |||
| 357 | #endif /* MODULE */ | ||
diff --git a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c new file mode 100644 index 00000000000..52c77cbe8c6 --- /dev/null +++ b/drivers/net/arcnet/com90io.c | |||
| @@ -0,0 +1,435 @@ | |||
| 1 | /* | ||
| 2 | * Linux ARCnet driver - COM90xx chipset (IO-mapped buffers) | ||
| 3 | * | ||
| 4 | * Written 1997 by David Woodhouse. | ||
| 5 | * Written 1994-1999 by Avery Pennarun. | ||
| 6 | * Written 1999-2000 by Martin Mares <mj@ucw.cz>. | ||
| 7 | * Derived from skeleton.c by Donald Becker. | ||
| 8 | * | ||
| 9 | * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) | ||
| 10 | * for sponsoring the further development of this driver. | ||
| 11 | * | ||
| 12 | * ********************** | ||
| 13 | * | ||
| 14 | * The original copyright of skeleton.c was as follows: | ||
| 15 | * | ||
| 16 | * skeleton.c Written 1993 by Donald Becker. | ||
| 17 | * Copyright 1993 United States Government as represented by the | ||
| 18 | * Director, National Security Agency. This software may only be used | ||
| 19 | * and distributed according to the terms of the GNU General Public License as | ||
| 20 | * modified by SRC, incorporated herein by reference. | ||
| 21 | * | ||
| 22 | * ********************** | ||
| 23 | * | ||
| 24 | * For more details, see drivers/net/arcnet.c | ||
| 25 | * | ||
| 26 | * ********************** | ||
| 27 | */ | ||
| 28 | #include <linux/kernel.h> | ||
| 29 | #include <linux/module.h> | ||
| 30 | #include <linux/moduleparam.h> | ||
| 31 | #include <linux/ioport.h> | ||
| 32 | #include <linux/slab.h> | ||
| 33 | #include <linux/delay.h> | ||
| 34 | #include <linux/netdevice.h> | ||
| 35 | #include <linux/bootmem.h> | ||
| 36 | #include <linux/init.h> | ||
| 37 | #include <asm/io.h> | ||
| 38 | #include <linux/arcdevice.h> | ||
| 39 | |||
| 40 | |||
| 41 | #define VERSION "arcnet: COM90xx IO-mapped mode support (by David Woodhouse et el.)\n" | ||
| 42 | |||
| 43 | |||
| 44 | /* Internal function declarations */ | ||
| 45 | |||
| 46 | static int com90io_found(struct net_device *dev); | ||
| 47 | static void com90io_command(struct net_device *dev, int command); | ||
| 48 | static int com90io_status(struct net_device *dev); | ||
| 49 | static void com90io_setmask(struct net_device *dev, int mask); | ||
| 50 | static int com90io_reset(struct net_device *dev, int really_reset); | ||
| 51 | static void com90io_copy_to_card(struct net_device *dev, int bufnum, int offset, | ||
| 52 | void *buf, int count); | ||
| 53 | static void com90io_copy_from_card(struct net_device *dev, int bufnum, int offset, | ||
| 54 | void *buf, int count); | ||
| 55 | |||
| 56 | |||
| 57 | /* Handy defines for ARCnet specific stuff */ | ||
| 58 | |||
| 59 | /* The number of low I/O ports used by the card. */ | ||
| 60 | #define ARCNET_TOTAL_SIZE 16 | ||
| 61 | |||
| 62 | /* COM 9026 controller chip --> ARCnet register addresses */ | ||
| 63 | #define _INTMASK (ioaddr+0) /* writable */ | ||
| 64 | #define _STATUS (ioaddr+0) /* readable */ | ||
| 65 | #define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */ | ||
| 66 | #define _RESET (ioaddr+8) /* software reset (on read) */ | ||
| 67 | #define _MEMDATA (ioaddr+12) /* Data port for IO-mapped memory */ | ||
| 68 | #define _ADDR_HI (ioaddr+15) /* Control registers for said */ | ||
| 69 | #define _ADDR_LO (ioaddr+14) | ||
| 70 | #define _CONFIG (ioaddr+2) /* Configuration register */ | ||
| 71 | |||
| 72 | #undef ASTATUS | ||
| 73 | #undef ACOMMAND | ||
| 74 | #undef AINTMASK | ||
| 75 | |||
| 76 | #define ASTATUS() inb(_STATUS) | ||
| 77 | #define ACOMMAND(cmd) outb((cmd),_COMMAND) | ||
| 78 | #define AINTMASK(msk) outb((msk),_INTMASK) | ||
| 79 | #define SETCONF() outb((lp->config),_CONFIG) | ||
| 80 | |||
| 81 | |||
| 82 | /**************************************************************************** | ||
| 83 | * * | ||
| 84 | * IO-mapped operation routines * | ||
| 85 | * * | ||
| 86 | ****************************************************************************/ | ||
| 87 | |||
| 88 | #undef ONE_AT_A_TIME_TX | ||
| 89 | #undef ONE_AT_A_TIME_RX | ||
| 90 | |||
| 91 | static u_char get_buffer_byte(struct net_device *dev, unsigned offset) | ||
| 92 | { | ||
| 93 | int ioaddr = dev->base_addr; | ||
| 94 | |||
| 95 | outb(offset >> 8, _ADDR_HI); | ||
| 96 | outb(offset & 0xff, _ADDR_LO); | ||
| 97 | |||
| 98 | return inb(_MEMDATA); | ||
| 99 | } | ||
| 100 | |||
| 101 | #ifdef ONE_AT_A_TIME_TX | ||
| 102 | static void put_buffer_byte(struct net_device *dev, unsigned offset, u_char datum) | ||
| 103 | { | ||
| 104 | int ioaddr = dev->base_addr; | ||
| 105 | |||
| 106 | outb(offset >> 8, _ADDR_HI); | ||
| 107 | outb(offset & 0xff, _ADDR_LO); | ||
| 108 | |||
| 109 | outb(datum, _MEMDATA); | ||
| 110 | } | ||
| 111 | |||
| 112 | #endif | ||
| 113 | |||
| 114 | |||
| 115 | static void get_whole_buffer(struct net_device *dev, unsigned offset, unsigned length, char *dest) | ||
| 116 | { | ||
| 117 | int ioaddr = dev->base_addr; | ||
| 118 | |||
| 119 | outb((offset >> 8) | AUTOINCflag, _ADDR_HI); | ||
| 120 | outb(offset & 0xff, _ADDR_LO); | ||
| 121 | |||
| 122 | while (length--) | ||
| 123 | #ifdef ONE_AT_A_TIME_RX | ||
| 124 | *(dest++) = get_buffer_byte(dev, offset++); | ||
| 125 | #else | ||
| 126 | *(dest++) = inb(_MEMDATA); | ||
| 127 | #endif | ||
| 128 | } | ||
| 129 | |||
| 130 | static void put_whole_buffer(struct net_device *dev, unsigned offset, unsigned length, char *dest) | ||
| 131 | { | ||
| 132 | int ioaddr = dev->base_addr; | ||
| 133 | |||
| 134 | outb((offset >> 8) | AUTOINCflag, _ADDR_HI); | ||
| 135 | outb(offset & 0xff, _ADDR_LO); | ||
| 136 | |||
| 137 | while (length--) | ||
| 138 | #ifdef ONE_AT_A_TIME_TX | ||
| 139 | put_buffer_byte(dev, offset++, *(dest++)); | ||
| 140 | #else | ||
| 141 | outb(*(dest++), _MEMDATA); | ||
| 142 | #endif | ||
| 143 | } | ||
| 144 | |||
| 145 | /* | ||
| 146 | * We cannot probe for an IO mapped card either, although we can check that | ||
| 147 | * it's where we were told it was, and even autoirq | ||
| 148 | */ | ||
| 149 | static int __init com90io_probe(struct net_device *dev) | ||
| 150 | { | ||
| 151 | int ioaddr = dev->base_addr, status; | ||
| 152 | unsigned long airqmask; | ||
| 153 | |||
| 154 | BUGLVL(D_NORMAL) printk(VERSION); | ||
| 155 | BUGLVL(D_NORMAL) printk("E-mail me if you actually test this driver, please!\n"); | ||
| 156 | |||
| 157 | if (!ioaddr) { | ||
| 158 | BUGMSG(D_NORMAL, "No autoprobe for IO mapped cards; you " | ||
| 159 | "must specify the base address!\n"); | ||
| 160 | return -ENODEV; | ||
| 161 | } | ||
| 162 | if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "com90io probe")) { | ||
| 163 | BUGMSG(D_INIT_REASONS, "IO check_region %x-%x failed.\n", | ||
| 164 | ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1); | ||
| 165 | return -ENXIO; | ||
| 166 | } | ||
| 167 | if (ASTATUS() == 0xFF) { | ||
| 168 | BUGMSG(D_INIT_REASONS, "IO address %x empty\n", ioaddr); | ||
| 169 | goto err_out; | ||
| 170 | } | ||
| 171 | inb(_RESET); | ||
| 172 | mdelay(RESETtime); | ||
| 173 | |||
| 174 | status = ASTATUS(); | ||
| 175 | |||
| 176 | if ((status & 0x9D) != (NORXflag | RECONflag | TXFREEflag | RESETflag)) { | ||
| 177 | BUGMSG(D_INIT_REASONS, "Status invalid (%Xh).\n", status); | ||
| 178 | goto err_out; | ||
| 179 | } | ||
| 180 | BUGMSG(D_INIT_REASONS, "Status after reset: %X\n", status); | ||
| 181 | |||
| 182 | ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear); | ||
| 183 | |||
| 184 | BUGMSG(D_INIT_REASONS, "Status after reset acknowledged: %X\n", status); | ||
| 185 | |||
| 186 | status = ASTATUS(); | ||
| 187 | |||
| 188 | if (status & RESETflag) { | ||
| 189 | BUGMSG(D_INIT_REASONS, "Eternal reset (status=%Xh)\n", status); | ||
| 190 | goto err_out; | ||
| 191 | } | ||
| 192 | outb((0x16 | IOMAPflag) & ~ENABLE16flag, _CONFIG); | ||
| 193 | |||
| 194 | /* Read first loc'n of memory */ | ||
| 195 | |||
| 196 | outb(AUTOINCflag, _ADDR_HI); | ||
| 197 | outb(0, _ADDR_LO); | ||
| 198 | |||
| 199 | if ((status = inb(_MEMDATA)) != 0xd1) { | ||
| 200 | BUGMSG(D_INIT_REASONS, "Signature byte not found" | ||
| 201 | " (%Xh instead).\n", status); | ||
| 202 | goto err_out; | ||
| 203 | } | ||
| 204 | if (!dev->irq) { | ||
| 205 | /* | ||
| 206 | * if we do this, we're sure to get an IRQ since the | ||
| 207 | * card has just reset and the NORXflag is on until | ||
| 208 | * we tell it to start receiving. | ||
| 209 | */ | ||
| 210 | |||
| 211 | airqmask = probe_irq_on(); | ||
| 212 | outb(NORXflag, _INTMASK); | ||
| 213 | udelay(1); | ||
| 214 | outb(0, _INTMASK); | ||
| 215 | dev->irq = probe_irq_off(airqmask); | ||
| 216 | |||
| 217 | if (dev->irq <= 0) { | ||
| 218 | BUGMSG(D_INIT_REASONS, "Autoprobe IRQ failed\n"); | ||
| 219 | goto err_out; | ||
| 220 | } | ||
| 221 | } | ||
| 222 | release_region(ioaddr, ARCNET_TOTAL_SIZE); /* end of probing */ | ||
| 223 | return com90io_found(dev); | ||
| 224 | |||
| 225 | err_out: | ||
| 226 | release_region(ioaddr, ARCNET_TOTAL_SIZE); | ||
| 227 | return -ENODEV; | ||
| 228 | } | ||
| 229 | |||
| 230 | |||
| 231 | /* Set up the struct net_device associated with this card. Called after | ||
| 232 | * probing succeeds. | ||
| 233 | */ | ||
| 234 | static int __init com90io_found(struct net_device *dev) | ||
| 235 | { | ||
| 236 | struct arcnet_local *lp; | ||
| 237 | int ioaddr = dev->base_addr; | ||
| 238 | int err; | ||
| 239 | |||
| 240 | /* Reserve the irq */ | ||
| 241 | if (request_irq(dev->irq, &arcnet_interrupt, 0, "arcnet (COM90xx-IO)", dev)) { | ||
| 242 | BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq); | ||
| 243 | return -ENODEV; | ||
| 244 | } | ||
| 245 | /* Reserve the I/O region - guaranteed to work by check_region */ | ||
| 246 | if (!request_region(dev->base_addr, ARCNET_TOTAL_SIZE, "arcnet (COM90xx-IO)")) { | ||
| 247 | free_irq(dev->irq, dev); | ||
| 248 | return -EBUSY; | ||
| 249 | } | ||
| 250 | |||
| 251 | lp = dev->priv; | ||
| 252 | lp->card_name = "COM90xx I/O"; | ||
| 253 | lp->hw.command = com90io_command; | ||
| 254 | lp->hw.status = com90io_status; | ||
| 255 | lp->hw.intmask = com90io_setmask; | ||
| 256 | lp->hw.reset = com90io_reset; | ||
| 257 | lp->hw.owner = THIS_MODULE; | ||
| 258 | lp->hw.copy_to_card = com90io_copy_to_card; | ||
| 259 | lp->hw.copy_from_card = com90io_copy_from_card; | ||
| 260 | |||
| 261 | lp->config = (0x16 | IOMAPflag) & ~ENABLE16flag; | ||
| 262 | SETCONF(); | ||
| 263 | |||
| 264 | /* get and check the station ID from offset 1 in shmem */ | ||
| 265 | |||
| 266 | dev->dev_addr[0] = get_buffer_byte(dev, 1); | ||
| 267 | |||
| 268 | err = register_netdev(dev); | ||
| 269 | if (err) { | ||
| 270 | outb((inb(_CONFIG) & ~IOMAPflag), _CONFIG); | ||
| 271 | free_irq(dev->irq, dev); | ||
| 272 | release_region(dev->base_addr, ARCNET_TOTAL_SIZE); | ||
| 273 | return err; | ||
| 274 | } | ||
| 275 | |||
| 276 | BUGMSG(D_NORMAL, "COM90IO: station %02Xh found at %03lXh, IRQ %d.\n", | ||
| 277 | dev->dev_addr[0], dev->base_addr, dev->irq); | ||
| 278 | |||
| 279 | return 0; | ||
| 280 | } | ||
| 281 | |||
| 282 | |||
| 283 | /* | ||
| 284 | * Do a hardware reset on the card, and set up necessary registers. | ||
| 285 | * | ||
| 286 | * This should be called as little as possible, because it disrupts the | ||
| 287 | * token on the network (causes a RECON) and requires a significant delay. | ||
| 288 | * | ||
| 289 | * However, it does make sure the card is in a defined state. | ||
| 290 | */ | ||
| 291 | static int com90io_reset(struct net_device *dev, int really_reset) | ||
| 292 | { | ||
| 293 | struct arcnet_local *lp = dev->priv; | ||
| 294 | short ioaddr = dev->base_addr; | ||
| 295 | |||
| 296 | BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n", dev->name, ASTATUS()); | ||
| 297 | |||
| 298 | if (really_reset) { | ||
| 299 | /* reset the card */ | ||
| 300 | inb(_RESET); | ||
| 301 | mdelay(RESETtime); | ||
| 302 | } | ||
| 303 | /* Set the thing to IO-mapped, 8-bit mode */ | ||
| 304 | lp->config = (0x1C | IOMAPflag) & ~ENABLE16flag; | ||
| 305 | SETCONF(); | ||
| 306 | |||
| 307 | ACOMMAND(CFLAGScmd | RESETclear); /* clear flags & end reset */ | ||
| 308 | ACOMMAND(CFLAGScmd | CONFIGclear); | ||
| 309 | |||
| 310 | /* verify that the ARCnet signature byte is present */ | ||
| 311 | if (get_buffer_byte(dev, 0) != TESTvalue) { | ||
| 312 | BUGMSG(D_NORMAL, "reset failed: TESTvalue not present.\n"); | ||
| 313 | return 1; | ||
| 314 | } | ||
| 315 | /* enable extended (512-byte) packets */ | ||
| 316 | ACOMMAND(CONFIGcmd | EXTconf); | ||
| 317 | |||
| 318 | /* done! return success. */ | ||
| 319 | return 0; | ||
| 320 | } | ||
| 321 | |||
| 322 | |||
| 323 | static void com90io_command(struct net_device *dev, int cmd) | ||
| 324 | { | ||
| 325 | short ioaddr = dev->base_addr; | ||
| 326 | |||
| 327 | ACOMMAND(cmd); | ||
| 328 | } | ||
| 329 | |||
| 330 | |||
| 331 | static int com90io_status(struct net_device *dev) | ||
| 332 | { | ||
| 333 | short ioaddr = dev->base_addr; | ||
| 334 | |||
| 335 | return ASTATUS(); | ||
| 336 | } | ||
| 337 | |||
| 338 | |||
| 339 | static void com90io_setmask(struct net_device *dev, int mask) | ||
| 340 | { | ||
| 341 | short ioaddr = dev->base_addr; | ||
| 342 | |||
| 343 | AINTMASK(mask); | ||
| 344 | } | ||
| 345 | |||
| 346 | static void com90io_copy_to_card(struct net_device *dev, int bufnum, int offset, | ||
| 347 | void *buf, int count) | ||
| 348 | { | ||
| 349 | TIME("put_whole_buffer", count, put_whole_buffer(dev, bufnum * 512 + offset, count, buf)); | ||
| 350 | } | ||
| 351 | |||
| 352 | |||
| 353 | static void com90io_copy_from_card(struct net_device *dev, int bufnum, int offset, | ||
| 354 | void *buf, int count) | ||
| 355 | { | ||
| 356 | TIME("get_whole_buffer", count, get_whole_buffer(dev, bufnum * 512 + offset, count, buf)); | ||
| 357 | } | ||
| 358 | |||
| 359 | static int io; /* use the insmod io= irq= shmem= options */ | ||
| 360 | static int irq; | ||
| 361 | static char device[9]; /* use eg. device=arc1 to change name */ | ||
| 362 | |||
| 363 | module_param(io, int, 0); | ||
| 364 | module_param(irq, int, 0); | ||
| 365 | module_param_string(device, device, sizeof(device), 0); | ||
| 366 | MODULE_LICENSE("GPL"); | ||
| 367 | |||
| 368 | #ifndef MODULE | ||
| 369 | static int __init com90io_setup(char *s) | ||
| 370 | { | ||
| 371 | int ints[4]; | ||
| 372 | s = get_options(s, 4, ints); | ||
| 373 | if (!ints[0]) | ||
| 374 | return 0; | ||
| 375 | switch (ints[0]) { | ||
| 376 | default: /* ERROR */ | ||
| 377 | printk("com90io: Too many arguments.\n"); | ||
| 378 | case 2: /* IRQ */ | ||
| 379 | irq = ints[2]; | ||
| 380 | case 1: /* IO address */ | ||
| 381 | io = ints[1]; | ||
| 382 | } | ||
| 383 | if (*s) | ||
| 384 | snprintf(device, sizeof(device), "%s", s); | ||
| 385 | return 1; | ||
| 386 | } | ||
| 387 | __setup("com90io=", com90io_setup); | ||
| 388 | #endif | ||
| 389 | |||
| 390 | static struct net_device *my_dev; | ||
| 391 | |||
| 392 | static int __init com90io_init(void) | ||
| 393 | { | ||
| 394 | struct net_device *dev; | ||
| 395 | int err; | ||
| 396 | |||
| 397 | dev = alloc_arcdev(device); | ||
| 398 | if (!dev) | ||
| 399 | return -ENOMEM; | ||
| 400 | |||
| 401 | SET_MODULE_OWNER(dev); | ||
| 402 | |||
| 403 | dev->base_addr = io; | ||
| 404 | dev->irq = irq; | ||
| 405 | if (dev->irq == 2) | ||
| 406 | dev->irq = 9; | ||
| 407 | |||
| 408 | err = com90io_probe(dev); | ||
| 409 | |||
| 410 | if (err) { | ||
| 411 | free_netdev(dev); | ||
| 412 | return err; | ||
| 413 | } | ||
| 414 | |||
| 415 | my_dev = dev; | ||
| 416 | return 0; | ||
| 417 | } | ||
| 418 | |||
| 419 | static void __exit com90io_exit(void) | ||
| 420 | { | ||
| 421 | struct net_device *dev = my_dev; | ||
| 422 | int ioaddr = dev->base_addr; | ||
| 423 | |||
| 424 | unregister_netdev(dev); | ||
| 425 | |||
| 426 | /* Set the thing back to MMAP mode, in case the old driver is loaded later */ | ||
| 427 | outb((inb(_CONFIG) & ~IOMAPflag), _CONFIG); | ||
| 428 | |||
| 429 | free_irq(dev->irq, dev); | ||
| 430 | release_region(dev->base_addr, ARCNET_TOTAL_SIZE); | ||
| 431 | free_netdev(dev); | ||
| 432 | } | ||
| 433 | |||
| 434 | module_init(com90io_init) | ||
| 435 | module_exit(com90io_exit) | ||
diff --git a/drivers/net/arcnet/com90xx.c b/drivers/net/arcnet/com90xx.c new file mode 100644 index 00000000000..6c2c9b9ac6d --- /dev/null +++ b/drivers/net/arcnet/com90xx.c | |||
| @@ -0,0 +1,646 @@ | |||
| 1 | /* | ||
| 2 | * Linux ARCnet driver - COM90xx chipset (memory-mapped buffers) | ||
| 3 | * | ||
| 4 | * Written 1994-1999 by Avery Pennarun. | ||
| 5 | * Written 1999 by Martin Mares <mj@ucw.cz>. | ||
| 6 | * Derived from skeleton.c by Donald Becker. | ||
| 7 | * | ||
| 8 | * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) | ||
| 9 | * for sponsoring the further development of this driver. | ||
| 10 | * | ||
| 11 | * ********************** | ||
| 12 | * | ||
| 13 | * The original copyright of skeleton.c was as follows: | ||
| 14 | * | ||
| 15 | * skeleton.c Written 1993 by Donald Becker. | ||
| 16 | * Copyright 1993 United States Government as represented by the | ||
| 17 | * Director, National Security Agency. This software may only be used | ||
| 18 | * and distributed according to the terms of the GNU General Public License as | ||
| 19 | * modified by SRC, incorporated herein by reference. | ||
| 20 | * | ||
| 21 | * ********************** | ||
| 22 | * | ||
| 23 | * For more details, see drivers/net/arcnet.c | ||
| 24 | * | ||
| 25 | * ********************** | ||
| 26 | */ | ||
| 27 | #include <linux/module.h> | ||
| 28 | #include <linux/moduleparam.h> | ||
| 29 | #include <linux/init.h> | ||
| 30 | #include <linux/ioport.h> | ||
| 31 | #include <linux/delay.h> | ||
| 32 | #include <linux/netdevice.h> | ||
| 33 | #include <asm/io.h> | ||
| 34 | #include <linux/arcdevice.h> | ||
| 35 | |||
| 36 | |||
| 37 | #define VERSION "arcnet: COM90xx chipset support\n" | ||
| 38 | |||
| 39 | |||
| 40 | /* Define this to speed up the autoprobe by assuming if only one io port and | ||
| 41 | * shmem are left in the list at Stage 5, they must correspond to each | ||
| 42 | * other. | ||
| 43 | * | ||
| 44 | * This is undefined by default because it might not always be true, and the | ||
| 45 | * extra check makes the autoprobe even more careful. Speed demons can turn | ||
| 46 | * it on - I think it should be fine if you only have one ARCnet card | ||
| 47 | * installed. | ||
| 48 | * | ||
| 49 | * If no ARCnet cards are installed, this delay never happens anyway and thus | ||
| 50 | * the option has no effect. | ||
| 51 | */ | ||
| 52 | #undef FAST_PROBE | ||
| 53 | |||
| 54 | |||
| 55 | /* Internal function declarations */ | ||
| 56 | static int com90xx_found(int ioaddr, int airq, u_long shmem); | ||
| 57 | static void com90xx_command(struct net_device *dev, int command); | ||
| 58 | static int com90xx_status(struct net_device *dev); | ||
| 59 | static void com90xx_setmask(struct net_device *dev, int mask); | ||
| 60 | static int com90xx_reset(struct net_device *dev, int really_reset); | ||
| 61 | static void com90xx_copy_to_card(struct net_device *dev, int bufnum, int offset, | ||
| 62 | void *buf, int count); | ||
| 63 | static void com90xx_copy_from_card(struct net_device *dev, int bufnum, int offset, | ||
| 64 | void *buf, int count); | ||
| 65 | |||
| 66 | /* Known ARCnet cards */ | ||
| 67 | |||
| 68 | static struct net_device *cards[16]; | ||
| 69 | static int numcards; | ||
| 70 | |||
| 71 | /* Handy defines for ARCnet specific stuff */ | ||
| 72 | |||
| 73 | /* The number of low I/O ports used by the card */ | ||
| 74 | #define ARCNET_TOTAL_SIZE 16 | ||
| 75 | |||
| 76 | /* Amount of I/O memory used by the card */ | ||
| 77 | #define BUFFER_SIZE (512) | ||
| 78 | #define MIRROR_SIZE (BUFFER_SIZE*4) | ||
| 79 | |||
| 80 | /* COM 9026 controller chip --> ARCnet register addresses */ | ||
| 81 | #define _INTMASK (ioaddr+0) /* writable */ | ||
| 82 | #define _STATUS (ioaddr+0) /* readable */ | ||
| 83 | #define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */ | ||
| 84 | #define _CONFIG (ioaddr+2) /* Configuration register */ | ||
| 85 | #define _RESET (ioaddr+8) /* software reset (on read) */ | ||
| 86 | #define _MEMDATA (ioaddr+12) /* Data port for IO-mapped memory */ | ||
| 87 | #define _ADDR_HI (ioaddr+15) /* Control registers for said */ | ||
| 88 | #define _ADDR_LO (ioaddr+14) | ||
| 89 | |||
| 90 | #undef ASTATUS | ||
| 91 | #undef ACOMMAND | ||
| 92 | #undef AINTMASK | ||
| 93 | |||
| 94 | #define ASTATUS() inb(_STATUS) | ||
| 95 | #define ACOMMAND(cmd) outb((cmd),_COMMAND) | ||
| 96 | #define AINTMASK(msk) outb((msk),_INTMASK) | ||
| 97 | |||
| 98 | |||
| 99 | static int com90xx_skip_probe __initdata = 0; | ||
| 100 | |||
| 101 | /* Module parameters */ | ||
| 102 | |||
| 103 | static int io; /* use the insmod io= irq= shmem= options */ | ||
| 104 | static int irq; | ||
| 105 | static int shmem; | ||
| 106 | static char device[9]; /* use eg. device=arc1 to change name */ | ||
| 107 | |||
| 108 | module_param(io, int, 0); | ||
| 109 | module_param(irq, int, 0); | ||
| 110 | module_param(shmem, int, 0); | ||
| 111 | module_param_string(device, device, sizeof(device), 0); | ||
| 112 | |||
| 113 | static void __init com90xx_probe(void) | ||
| 114 | { | ||
| 115 | int count, status, ioaddr, numprint, airq, openparen = 0; | ||
| 116 | unsigned long airqmask; | ||
| 117 | int ports[(0x3f0 - 0x200) / 16 + 1] = | ||
| 118 | {0}; | ||
| 119 | u_long shmems[(0xFF800 - 0xA0000) / 2048 + 1] = | ||
| 120 | {0}; | ||
| 121 | int numports, numshmems, *port; | ||
| 122 | u_long *p; | ||
| 123 | |||
| 124 | if (!io && !irq && !shmem && !*device && com90xx_skip_probe) | ||
| 125 | return; | ||
| 126 | |||
| 127 | BUGLVL(D_NORMAL) printk(VERSION); | ||
| 128 | |||
| 129 | /* set up the arrays where we'll store the possible probe addresses */ | ||
| 130 | numports = numshmems = 0; | ||
| 131 | if (io) | ||
| 132 | ports[numports++] = io; | ||
| 133 | else | ||
| 134 | for (count = 0x200; count <= 0x3f0; count += 16) | ||
| 135 | ports[numports++] = count; | ||
| 136 | if (shmem) | ||
| 137 | shmems[numshmems++] = shmem; | ||
| 138 | else | ||
| 139 | for (count = 0xA0000; count <= 0xFF800; count += 2048) | ||
| 140 | shmems[numshmems++] = count; | ||
| 141 | |||
| 142 | /* Stage 1: abandon any reserved ports, or ones with status==0xFF | ||
| 143 | * (empty), and reset any others by reading the reset port. | ||
| 144 | */ | ||
| 145 | numprint = -1; | ||
| 146 | for (port = &ports[0]; port - ports < numports; port++) { | ||
| 147 | numprint++; | ||
| 148 | numprint %= 8; | ||
| 149 | if (!numprint) { | ||
| 150 | BUGMSG2(D_INIT, "\n"); | ||
| 151 | BUGMSG2(D_INIT, "S1: "); | ||
| 152 | } | ||
| 153 | BUGMSG2(D_INIT, "%Xh ", *port); | ||
| 154 | |||
| 155 | ioaddr = *port; | ||
| 156 | |||
| 157 | if (!request_region(*port, ARCNET_TOTAL_SIZE, "arcnet (90xx)")) { | ||
| 158 | BUGMSG2(D_INIT_REASONS, "(request_region)\n"); | ||
| 159 | BUGMSG2(D_INIT_REASONS, "S1: "); | ||
| 160 | BUGLVL(D_INIT_REASONS) numprint = 0; | ||
| 161 | *port-- = ports[--numports]; | ||
| 162 | continue; | ||
| 163 | } | ||
| 164 | if (ASTATUS() == 0xFF) { | ||
| 165 | BUGMSG2(D_INIT_REASONS, "(empty)\n"); | ||
| 166 | BUGMSG2(D_INIT_REASONS, "S1: "); | ||
| 167 | BUGLVL(D_INIT_REASONS) numprint = 0; | ||
| 168 | release_region(*port, ARCNET_TOTAL_SIZE); | ||
| 169 | *port-- = ports[--numports]; | ||
| 170 | continue; | ||
| 171 | } | ||
| 172 | inb(_RESET); /* begin resetting card */ | ||
| 173 | |||
| 174 | BUGMSG2(D_INIT_REASONS, "\n"); | ||
| 175 | BUGMSG2(D_INIT_REASONS, "S1: "); | ||
| 176 | BUGLVL(D_INIT_REASONS) numprint = 0; | ||
| 177 | } | ||
| 178 | BUGMSG2(D_INIT, "\n"); | ||
| 179 | |||
| 180 | if (!numports) { | ||
| 181 | BUGMSG2(D_NORMAL, "S1: No ARCnet cards found.\n"); | ||
| 182 | return; | ||
| 183 | } | ||
| 184 | /* Stage 2: we have now reset any possible ARCnet cards, so we can't | ||
| 185 | * do anything until they finish. If D_INIT, print the list of | ||
| 186 | * cards that are left. | ||
| 187 | */ | ||
| 188 | numprint = -1; | ||
| 189 | for (port = &ports[0]; port < ports + numports; port++) { | ||
| 190 | numprint++; | ||
| 191 | numprint %= 8; | ||
| 192 | if (!numprint) { | ||
| 193 | BUGMSG2(D_INIT, "\n"); | ||
| 194 | BUGMSG2(D_INIT, "S2: "); | ||
| 195 | } | ||
| 196 | BUGMSG2(D_INIT, "%Xh ", *port); | ||
| 197 | } | ||
| 198 | BUGMSG2(D_INIT, "\n"); | ||
| 199 | mdelay(RESETtime); | ||
| 200 | |||
| 201 | /* Stage 3: abandon any shmem addresses that don't have the signature | ||
| 202 | * 0xD1 byte in the right place, or are read-only. | ||
| 203 | */ | ||
| 204 | numprint = -1; | ||
| 205 | for (p = &shmems[0]; p < shmems + numshmems; p++) { | ||
| 206 | u_long ptr = *p; | ||
| 207 | |||
| 208 | numprint++; | ||
| 209 | numprint %= 8; | ||
| 210 | if (!numprint) { | ||
| 211 | BUGMSG2(D_INIT, "\n"); | ||
| 212 | BUGMSG2(D_INIT, "S3: "); | ||
| 213 | } | ||
| 214 | BUGMSG2(D_INIT, "%lXh ", *p); | ||
| 215 | |||
| 216 | if (!request_mem_region(*p, BUFFER_SIZE, "arcnet (90xx)")) { | ||
| 217 | BUGMSG2(D_INIT_REASONS, "(request_mem_region)\n"); | ||
| 218 | BUGMSG2(D_INIT_REASONS, "Stage 3: "); | ||
| 219 | BUGLVL(D_INIT_REASONS) numprint = 0; | ||
| 220 | *p-- = shmems[--numshmems]; | ||
| 221 | continue; | ||
| 222 | } | ||
| 223 | if (isa_readb(ptr) != TESTvalue) { | ||
| 224 | BUGMSG2(D_INIT_REASONS, "(%02Xh != %02Xh)\n", | ||
| 225 | isa_readb(ptr), TESTvalue); | ||
| 226 | BUGMSG2(D_INIT_REASONS, "S3: "); | ||
| 227 | BUGLVL(D_INIT_REASONS) numprint = 0; | ||
| 228 | release_mem_region(*p, BUFFER_SIZE); | ||
| 229 | *p-- = shmems[--numshmems]; | ||
| 230 | continue; | ||
| 231 | } | ||
| 232 | /* By writing 0x42 to the TESTvalue location, we also make | ||
| 233 | * sure no "mirror" shmem areas show up - if they occur | ||
| 234 | * in another pass through this loop, they will be discarded | ||
| 235 | * because *cptr != TESTvalue. | ||
| 236 | */ | ||
| 237 | isa_writeb(0x42, ptr); | ||
| 238 | if (isa_readb(ptr) != 0x42) { | ||
| 239 | BUGMSG2(D_INIT_REASONS, "(read only)\n"); | ||
| 240 | BUGMSG2(D_INIT_REASONS, "S3: "); | ||
| 241 | release_mem_region(*p, BUFFER_SIZE); | ||
| 242 | *p-- = shmems[--numshmems]; | ||
| 243 | continue; | ||
| 244 | } | ||
| 245 | BUGMSG2(D_INIT_REASONS, "\n"); | ||
| 246 | BUGMSG2(D_INIT_REASONS, "S3: "); | ||
| 247 | BUGLVL(D_INIT_REASONS) numprint = 0; | ||
| 248 | } | ||
| 249 | BUGMSG2(D_INIT, "\n"); | ||
| 250 | |||
| 251 | if (!numshmems) { | ||
| 252 | BUGMSG2(D_NORMAL, "S3: No ARCnet cards found.\n"); | ||
| 253 | for (port = &ports[0]; port < ports + numports; port++) | ||
| 254 | release_region(*port, ARCNET_TOTAL_SIZE); | ||
| 255 | return; | ||
| 256 | } | ||
| 257 | /* Stage 4: something of a dummy, to report the shmems that are | ||
| 258 | * still possible after stage 3. | ||
| 259 | */ | ||
| 260 | numprint = -1; | ||
| 261 | for (p = &shmems[0]; p < shmems + numshmems; p++) { | ||
| 262 | numprint++; | ||
| 263 | numprint %= 8; | ||
| 264 | if (!numprint) { | ||
| 265 | BUGMSG2(D_INIT, "\n"); | ||
| 266 | BUGMSG2(D_INIT, "S4: "); | ||
| 267 | } | ||
| 268 | BUGMSG2(D_INIT, "%lXh ", *p); | ||
| 269 | } | ||
| 270 | BUGMSG2(D_INIT, "\n"); | ||
| 271 | |||
| 272 | /* Stage 5: for any ports that have the correct status, can disable | ||
| 273 | * the RESET flag, and (if no irq is given) generate an autoirq, | ||
| 274 | * register an ARCnet device. | ||
| 275 | * | ||
| 276 | * Currently, we can only register one device per probe, so quit | ||
| 277 | * after the first one is found. | ||
| 278 | */ | ||
| 279 | numprint = -1; | ||
| 280 | for (port = &ports[0]; port < ports + numports; port++) { | ||
| 281 | int found = 0; | ||
| 282 | numprint++; | ||
| 283 | numprint %= 8; | ||
| 284 | if (!numprint) { | ||
| 285 | BUGMSG2(D_INIT, "\n"); | ||
| 286 | BUGMSG2(D_INIT, "S5: "); | ||
| 287 | } | ||
| 288 | BUGMSG2(D_INIT, "%Xh ", *port); | ||
| 289 | |||
| 290 | ioaddr = *port; | ||
| 291 | status = ASTATUS(); | ||
| 292 | |||
| 293 | if ((status & 0x9D) | ||
| 294 | != (NORXflag | RECONflag | TXFREEflag | RESETflag)) { | ||
| 295 | BUGMSG2(D_INIT_REASONS, "(status=%Xh)\n", status); | ||
| 296 | BUGMSG2(D_INIT_REASONS, "S5: "); | ||
| 297 | BUGLVL(D_INIT_REASONS) numprint = 0; | ||
| 298 | release_region(*port, ARCNET_TOTAL_SIZE); | ||
| 299 | *port-- = ports[--numports]; | ||
| 300 | continue; | ||
| 301 | } | ||
| 302 | ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear); | ||
| 303 | status = ASTATUS(); | ||
| 304 | if (status & RESETflag) { | ||
| 305 | BUGMSG2(D_INIT_REASONS, " (eternal reset, status=%Xh)\n", | ||
| 306 | status); | ||
| 307 | BUGMSG2(D_INIT_REASONS, "S5: "); | ||
| 308 | BUGLVL(D_INIT_REASONS) numprint = 0; | ||
| 309 | release_region(*port, ARCNET_TOTAL_SIZE); | ||
| 310 | *port-- = ports[--numports]; | ||
| 311 | continue; | ||
| 312 | } | ||
| 313 | /* skip this completely if an IRQ was given, because maybe | ||
| 314 | * we're on a machine that locks during autoirq! | ||
| 315 | */ | ||
| 316 | if (!irq) { | ||
| 317 | /* if we do this, we're sure to get an IRQ since the | ||
| 318 | * card has just reset and the NORXflag is on until | ||
| 319 | * we tell it to start receiving. | ||
| 320 | */ | ||
| 321 | airqmask = probe_irq_on(); | ||
| 322 | AINTMASK(NORXflag); | ||
| 323 | udelay(1); | ||
| 324 | AINTMASK(0); | ||
| 325 | airq = probe_irq_off(airqmask); | ||
| 326 | |||
| 327 | if (airq <= 0) { | ||
| 328 | BUGMSG2(D_INIT_REASONS, "(airq=%d)\n", airq); | ||
| 329 | BUGMSG2(D_INIT_REASONS, "S5: "); | ||
| 330 | BUGLVL(D_INIT_REASONS) numprint = 0; | ||
| 331 | release_region(*port, ARCNET_TOTAL_SIZE); | ||
| 332 | *port-- = ports[--numports]; | ||
| 333 | continue; | ||
| 334 | } | ||
| 335 | } else { | ||
| 336 | airq = irq; | ||
| 337 | } | ||
| 338 | |||
| 339 | BUGMSG2(D_INIT, "(%d,", airq); | ||
| 340 | openparen = 1; | ||
| 341 | |||
| 342 | /* Everything seems okay. But which shmem, if any, puts | ||
| 343 | * back its signature byte when the card is reset? | ||
| 344 | * | ||
| 345 | * If there are multiple cards installed, there might be | ||
| 346 | * multiple shmems still in the list. | ||
| 347 | */ | ||
| 348 | #ifdef FAST_PROBE | ||
| 349 | if (numports > 1 || numshmems > 1) { | ||
| 350 | inb(_RESET); | ||
| 351 | mdelay(RESETtime); | ||
| 352 | } else { | ||
| 353 | /* just one shmem and port, assume they match */ | ||
| 354 | isa_writeb(TESTvalue, shmems[0]); | ||
| 355 | } | ||
| 356 | #else | ||
| 357 | inb(_RESET); | ||
| 358 | mdelay(RESETtime); | ||
| 359 | #endif | ||
| 360 | |||
| 361 | for (p = &shmems[0]; p < shmems + numshmems; p++) { | ||
| 362 | u_long ptr = *p; | ||
| 363 | |||
| 364 | if (isa_readb(ptr) == TESTvalue) { /* found one */ | ||
| 365 | BUGMSG2(D_INIT, "%lXh)\n", *p); | ||
| 366 | openparen = 0; | ||
| 367 | |||
| 368 | /* register the card */ | ||
| 369 | if (com90xx_found(*port, airq, *p) == 0) | ||
| 370 | found = 1; | ||
| 371 | numprint = -1; | ||
| 372 | |||
| 373 | /* remove shmem from the list */ | ||
| 374 | *p = shmems[--numshmems]; | ||
| 375 | break; /* go to the next I/O port */ | ||
| 376 | } else { | ||
| 377 | BUGMSG2(D_INIT_REASONS, "%Xh-", isa_readb(ptr)); | ||
| 378 | } | ||
| 379 | } | ||
| 380 | |||
| 381 | if (openparen) { | ||
| 382 | BUGLVL(D_INIT) printk("no matching shmem)\n"); | ||
| 383 | BUGLVL(D_INIT_REASONS) printk("S5: "); | ||
| 384 | BUGLVL(D_INIT_REASONS) numprint = 0; | ||
| 385 | } | ||
| 386 | if (!found) | ||
| 387 | release_region(*port, ARCNET_TOTAL_SIZE); | ||
| 388 | *port-- = ports[--numports]; | ||
| 389 | } | ||
| 390 | |||
| 391 | BUGLVL(D_INIT_REASONS) printk("\n"); | ||
| 392 | |||
| 393 | /* Now put back TESTvalue on all leftover shmems. */ | ||
| 394 | for (p = &shmems[0]; p < shmems + numshmems; p++) { | ||
| 395 | isa_writeb(TESTvalue, *p); | ||
| 396 | release_mem_region(*p, BUFFER_SIZE); | ||
| 397 | } | ||
| 398 | } | ||
| 399 | |||
| 400 | |||
| 401 | /* Set up the struct net_device associated with this card. Called after | ||
| 402 | * probing succeeds. | ||
| 403 | */ | ||
| 404 | static int __init com90xx_found(int ioaddr, int airq, u_long shmem) | ||
| 405 | { | ||
| 406 | struct net_device *dev = NULL; | ||
| 407 | struct arcnet_local *lp; | ||
| 408 | u_long first_mirror, last_mirror; | ||
| 409 | int mirror_size; | ||
| 410 | |||
| 411 | /* allocate struct net_device */ | ||
| 412 | dev = alloc_arcdev(device); | ||
| 413 | if (!dev) { | ||
| 414 | BUGMSG2(D_NORMAL, "com90xx: Can't allocate device!\n"); | ||
| 415 | release_mem_region(shmem, BUFFER_SIZE); | ||
| 416 | return -ENOMEM; | ||
| 417 | } | ||
| 418 | lp = dev->priv; | ||
| 419 | /* find the real shared memory start/end points, including mirrors */ | ||
| 420 | |||
| 421 | /* guess the actual size of one "memory mirror" - the number of | ||
| 422 | * bytes between copies of the shared memory. On most cards, it's | ||
| 423 | * 2k (or there are no mirrors at all) but on some, it's 4k. | ||
| 424 | */ | ||
| 425 | mirror_size = MIRROR_SIZE; | ||
| 426 | if (isa_readb(shmem) == TESTvalue | ||
| 427 | && isa_readb(shmem - mirror_size) != TESTvalue | ||
| 428 | && isa_readb(shmem - 2 * mirror_size) == TESTvalue) | ||
| 429 | mirror_size *= 2; | ||
| 430 | |||
| 431 | first_mirror = last_mirror = shmem; | ||
| 432 | while (isa_readb(first_mirror) == TESTvalue) | ||
| 433 | first_mirror -= mirror_size; | ||
| 434 | first_mirror += mirror_size; | ||
| 435 | |||
| 436 | while (isa_readb(last_mirror) == TESTvalue) | ||
| 437 | last_mirror += mirror_size; | ||
| 438 | last_mirror -= mirror_size; | ||
| 439 | |||
| 440 | dev->mem_start = first_mirror; | ||
| 441 | dev->mem_end = last_mirror + MIRROR_SIZE - 1; | ||
| 442 | |||
| 443 | release_mem_region(shmem, BUFFER_SIZE); | ||
| 444 | if (!request_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1, "arcnet (90xx)")) | ||
| 445 | goto err_free_dev; | ||
| 446 | |||
| 447 | /* reserve the irq */ | ||
| 448 | if (request_irq(airq, &arcnet_interrupt, 0, "arcnet (90xx)", dev)) { | ||
| 449 | BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", airq); | ||
| 450 | goto err_release_mem; | ||
| 451 | } | ||
| 452 | dev->irq = airq; | ||
| 453 | |||
| 454 | /* Initialize the rest of the device structure. */ | ||
| 455 | lp->card_name = "COM90xx"; | ||
| 456 | lp->hw.command = com90xx_command; | ||
| 457 | lp->hw.status = com90xx_status; | ||
| 458 | lp->hw.intmask = com90xx_setmask; | ||
| 459 | lp->hw.reset = com90xx_reset; | ||
| 460 | lp->hw.owner = THIS_MODULE; | ||
| 461 | lp->hw.copy_to_card = com90xx_copy_to_card; | ||
| 462 | lp->hw.copy_from_card = com90xx_copy_from_card; | ||
| 463 | lp->mem_start = ioremap(dev->mem_start, dev->mem_end - dev->mem_start + 1); | ||
| 464 | if (!lp->mem_start) { | ||
| 465 | BUGMSG(D_NORMAL, "Can't remap device memory!\n"); | ||
| 466 | goto err_free_irq; | ||
| 467 | } | ||
| 468 | |||
| 469 | /* get and check the station ID from offset 1 in shmem */ | ||
| 470 | dev->dev_addr[0] = readb(lp->mem_start + 1); | ||
| 471 | |||
| 472 | dev->base_addr = ioaddr; | ||
| 473 | |||
| 474 | BUGMSG(D_NORMAL, "COM90xx station %02Xh found at %03lXh, IRQ %d, " | ||
| 475 | "ShMem %lXh (%ld*%xh).\n", | ||
| 476 | dev->dev_addr[0], | ||
| 477 | dev->base_addr, dev->irq, dev->mem_start, | ||
| 478 | (dev->mem_end - dev->mem_start + 1) / mirror_size, mirror_size); | ||
| 479 | |||
| 480 | if (register_netdev(dev)) | ||
| 481 | goto err_unmap; | ||
| 482 | |||
| 483 | cards[numcards++] = dev; | ||
| 484 | return 0; | ||
| 485 | |||
| 486 | err_unmap: | ||
| 487 | iounmap(lp->mem_start); | ||
| 488 | err_free_irq: | ||
| 489 | free_irq(dev->irq, dev); | ||
| 490 | err_release_mem: | ||
| 491 | release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); | ||
| 492 | err_free_dev: | ||
| 493 | free_netdev(dev); | ||
| 494 | return -EIO; | ||
| 495 | } | ||
| 496 | |||
| 497 | |||
| 498 | static void com90xx_command(struct net_device *dev, int cmd) | ||
| 499 | { | ||
| 500 | short ioaddr = dev->base_addr; | ||
| 501 | |||
| 502 | ACOMMAND(cmd); | ||
| 503 | } | ||
| 504 | |||
| 505 | |||
| 506 | static int com90xx_status(struct net_device *dev) | ||
| 507 | { | ||
| 508 | short ioaddr = dev->base_addr; | ||
| 509 | |||
| 510 | return ASTATUS(); | ||
| 511 | } | ||
| 512 | |||
| 513 | |||
| 514 | static void com90xx_setmask(struct net_device *dev, int mask) | ||
| 515 | { | ||
| 516 | short ioaddr = dev->base_addr; | ||
| 517 | |||
| 518 | AINTMASK(mask); | ||
| 519 | } | ||
| 520 | |||
| 521 | |||
| 522 | /* | ||
| 523 | * Do a hardware reset on the card, and set up necessary registers. | ||
| 524 | * | ||
| 525 | * This should be called as little as possible, because it disrupts the | ||
| 526 | * token on the network (causes a RECON) and requires a significant delay. | ||
| 527 | * | ||
| 528 | * However, it does make sure the card is in a defined state. | ||
| 529 | */ | ||
| 530 | int com90xx_reset(struct net_device *dev, int really_reset) | ||
| 531 | { | ||
| 532 | struct arcnet_local *lp = dev->priv; | ||
| 533 | short ioaddr = dev->base_addr; | ||
| 534 | |||
| 535 | BUGMSG(D_INIT, "Resetting (status=%02Xh)\n", ASTATUS()); | ||
| 536 | |||
| 537 | if (really_reset) { | ||
| 538 | /* reset the card */ | ||
| 539 | inb(_RESET); | ||
| 540 | mdelay(RESETtime); | ||
| 541 | } | ||
| 542 | ACOMMAND(CFLAGScmd | RESETclear); /* clear flags & end reset */ | ||
| 543 | ACOMMAND(CFLAGScmd | CONFIGclear); | ||
| 544 | |||
| 545 | /* don't do this until we verify that it doesn't hurt older cards! */ | ||
| 546 | /* outb(inb(_CONFIG) | ENABLE16flag, _CONFIG); */ | ||
| 547 | |||
| 548 | /* verify that the ARCnet signature byte is present */ | ||
| 549 | if (readb(lp->mem_start) != TESTvalue) { | ||
| 550 | if (really_reset) | ||
| 551 | BUGMSG(D_NORMAL, "reset failed: TESTvalue not present.\n"); | ||
| 552 | return 1; | ||
| 553 | } | ||
| 554 | /* enable extended (512-byte) packets */ | ||
| 555 | ACOMMAND(CONFIGcmd | EXTconf); | ||
| 556 | |||
| 557 | /* clean out all the memory to make debugging make more sense :) */ | ||
| 558 | BUGLVL(D_DURING) | ||
| 559 | memset_io(lp->mem_start, 0x42, 2048); | ||
| 560 | |||
| 561 | /* done! return success. */ | ||
| 562 | return 0; | ||
| 563 | } | ||
| 564 | |||
| 565 | static void com90xx_copy_to_card(struct net_device *dev, int bufnum, int offset, | ||
| 566 | void *buf, int count) | ||
| 567 | { | ||
| 568 | struct arcnet_local *lp = dev->priv; | ||
| 569 | void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset; | ||
| 570 | TIME("memcpy_toio", count, memcpy_toio(memaddr, buf, count)); | ||
| 571 | } | ||
| 572 | |||
| 573 | |||
| 574 | static void com90xx_copy_from_card(struct net_device *dev, int bufnum, int offset, | ||
| 575 | void *buf, int count) | ||
| 576 | { | ||
| 577 | struct arcnet_local *lp = dev->priv; | ||
| 578 | void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset; | ||
| 579 | TIME("memcpy_fromio", count, memcpy_fromio(buf, memaddr, count)); | ||
| 580 | } | ||
| 581 | |||
| 582 | |||
| 583 | MODULE_LICENSE("GPL"); | ||
| 584 | |||
| 585 | static int __init com90xx_init(void) | ||
| 586 | { | ||
| 587 | if (irq == 2) | ||
| 588 | irq = 9; | ||
| 589 | com90xx_probe(); | ||
| 590 | if (!numcards) | ||
| 591 | return -EIO; | ||
| 592 | return 0; | ||
| 593 | } | ||
| 594 | |||
| 595 | static void __exit com90xx_exit(void) | ||
| 596 | { | ||
| 597 | struct net_device *dev; | ||
| 598 | struct arcnet_local *lp; | ||
| 599 | int count; | ||
| 600 | |||
| 601 | for (count = 0; count < numcards; count++) { | ||
| 602 | dev = cards[count]; | ||
| 603 | lp = dev->priv; | ||
| 604 | |||
| 605 | unregister_netdev(dev); | ||
| 606 | free_irq(dev->irq, dev); | ||
| 607 | iounmap(lp->mem_start); | ||
| 608 | release_region(dev->base_addr, ARCNET_TOTAL_SIZE); | ||
| 609 | release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); | ||
| 610 | free_netdev(dev); | ||
| 611 | } | ||
| 612 | } | ||
| 613 | |||
| 614 | module_init(com90xx_init); | ||
| 615 | module_exit(com90xx_exit); | ||
| 616 | |||
| 617 | #ifndef MODULE | ||
| 618 | static int __init com90xx_setup(char *s) | ||
| 619 | { | ||
| 620 | int ints[8]; | ||
| 621 | |||
| 622 | s = get_options(s, 8, ints); | ||
| 623 | if (!ints[0] && !*s) { | ||
| 624 | printk("com90xx: Disabled.\n"); | ||
| 625 | return 1; | ||
| 626 | } | ||
| 627 | |||
| 628 | switch (ints[0]) { | ||
| 629 | default: /* ERROR */ | ||
| 630 | printk("com90xx: Too many arguments.\n"); | ||
| 631 | case 3: /* Mem address */ | ||
| 632 | shmem = ints[3]; | ||
| 633 | case 2: /* IRQ */ | ||
| 634 | irq = ints[2]; | ||
| 635 | case 1: /* IO address */ | ||
| 636 | io = ints[1]; | ||
| 637 | } | ||
| 638 | |||
| 639 | if (*s) | ||
| 640 | snprintf(device, sizeof(device), "%s", s); | ||
| 641 | |||
| 642 | return 1; | ||
| 643 | } | ||
| 644 | |||
| 645 | __setup("com90xx=", com90xx_setup); | ||
| 646 | #endif | ||
diff --git a/drivers/net/arcnet/rfc1051.c b/drivers/net/arcnet/rfc1051.c new file mode 100644 index 00000000000..6d7913704fb --- /dev/null +++ b/drivers/net/arcnet/rfc1051.c | |||
| @@ -0,0 +1,253 @@ | |||
| 1 | /* | ||
| 2 | * Linux ARCnet driver - RFC1051 ("simple" standard) packet encapsulation | ||
| 3 | * | ||
| 4 | * Written 1994-1999 by Avery Pennarun. | ||
| 5 | * Derived from skeleton.c by Donald Becker. | ||
| 6 | * | ||
| 7 | * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) | ||
| 8 | * for sponsoring the further development of this driver. | ||
| 9 | * | ||
| 10 | * ********************** | ||
| 11 | * | ||
| 12 | * The original copyright of skeleton.c was as follows: | ||
| 13 | * | ||
| 14 | * skeleton.c Written 1993 by Donald Becker. | ||
| 15 | * Copyright 1993 United States Government as represented by the | ||
| 16 | * Director, National Security Agency. This software may only be used | ||
| 17 | * and distributed according to the terms of the GNU General Public License as | ||
| 18 | * modified by SRC, incorporated herein by reference. | ||
| 19 | * | ||
| 20 | * ********************** | ||
| 21 | * | ||
| 22 | * For more details, see drivers/net/arcnet.c | ||
| 23 | * | ||
| 24 | * ********************** | ||
| 25 | */ | ||
| 26 | #include <linux/module.h> | ||
| 27 | #include <linux/init.h> | ||
| 28 | #include <linux/if_arp.h> | ||
| 29 | #include <net/arp.h> | ||
| 30 | #include <linux/netdevice.h> | ||
| 31 | #include <linux/skbuff.h> | ||
| 32 | #include <linux/arcdevice.h> | ||
| 33 | |||
| 34 | #define VERSION "arcnet: RFC1051 \"simple standard\" (`s') encapsulation support loaded.\n" | ||
| 35 | |||
| 36 | |||
| 37 | static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev); | ||
| 38 | static void rx(struct net_device *dev, int bufnum, | ||
| 39 | struct archdr *pkthdr, int length); | ||
| 40 | static int build_header(struct sk_buff *skb, struct net_device *dev, | ||
| 41 | unsigned short type, uint8_t daddr); | ||
| 42 | static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, | ||
| 43 | int bufnum); | ||
| 44 | |||
| 45 | |||
| 46 | struct ArcProto rfc1051_proto = | ||
| 47 | { | ||
| 48 | .suffix = 's', | ||
| 49 | .mtu = XMTU - RFC1051_HDR_SIZE, | ||
| 50 | .is_ip = 1, | ||
| 51 | .rx = rx, | ||
| 52 | .build_header = build_header, | ||
| 53 | .prepare_tx = prepare_tx, | ||
| 54 | .continue_tx = NULL, | ||
| 55 | .ack_tx = NULL | ||
| 56 | }; | ||
| 57 | |||
| 58 | |||
| 59 | static int __init arcnet_rfc1051_init(void) | ||
| 60 | { | ||
| 61 | printk(VERSION); | ||
| 62 | |||
| 63 | arc_proto_map[ARC_P_IP_RFC1051] | ||
| 64 | = arc_proto_map[ARC_P_ARP_RFC1051] | ||
| 65 | = &rfc1051_proto; | ||
| 66 | |||
| 67 | /* if someone else already owns the broadcast, we won't take it */ | ||
| 68 | if (arc_bcast_proto == arc_proto_default) | ||
| 69 | arc_bcast_proto = &rfc1051_proto; | ||
| 70 | |||
| 71 | return 0; | ||
| 72 | } | ||
| 73 | |||
| 74 | static void __exit arcnet_rfc1051_exit(void) | ||
| 75 | { | ||
| 76 | arcnet_unregister_proto(&rfc1051_proto); | ||
| 77 | } | ||
| 78 | |||
| 79 | module_init(arcnet_rfc1051_init); | ||
| 80 | module_exit(arcnet_rfc1051_exit); | ||
| 81 | |||
| 82 | MODULE_LICENSE("GPL"); | ||
| 83 | |||
| 84 | /* | ||
| 85 | * Determine a packet's protocol ID. | ||
| 86 | * | ||
| 87 | * With ARCnet we have to convert everything to Ethernet-style stuff. | ||
| 88 | */ | ||
| 89 | static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev) | ||
| 90 | { | ||
| 91 | struct arcnet_local *lp = dev->priv; | ||
| 92 | struct archdr *pkt = (struct archdr *) skb->data; | ||
| 93 | struct arc_rfc1051 *soft = &pkt->soft.rfc1051; | ||
| 94 | int hdr_size = ARC_HDR_SIZE + RFC1051_HDR_SIZE; | ||
| 95 | |||
| 96 | /* Pull off the arcnet header. */ | ||
| 97 | skb->mac.raw = skb->data; | ||
| 98 | skb_pull(skb, hdr_size); | ||
| 99 | |||
| 100 | if (pkt->hard.dest == 0) | ||
| 101 | skb->pkt_type = PACKET_BROADCAST; | ||
| 102 | else if (dev->flags & IFF_PROMISC) { | ||
| 103 | /* if we're not sending to ourselves :) */ | ||
| 104 | if (pkt->hard.dest != dev->dev_addr[0]) | ||
| 105 | skb->pkt_type = PACKET_OTHERHOST; | ||
| 106 | } | ||
| 107 | /* now return the protocol number */ | ||
| 108 | switch (soft->proto) { | ||
| 109 | case ARC_P_IP_RFC1051: | ||
| 110 | return htons(ETH_P_IP); | ||
| 111 | case ARC_P_ARP_RFC1051: | ||
| 112 | return htons(ETH_P_ARP); | ||
| 113 | |||
| 114 | default: | ||
| 115 | lp->stats.rx_errors++; | ||
| 116 | lp->stats.rx_crc_errors++; | ||
| 117 | return 0; | ||
| 118 | } | ||
| 119 | |||
| 120 | return htons(ETH_P_IP); | ||
| 121 | } | ||
| 122 | |||
| 123 | |||
| 124 | /* packet receiver */ | ||
| 125 | static void rx(struct net_device *dev, int bufnum, | ||
| 126 | struct archdr *pkthdr, int length) | ||
| 127 | { | ||
| 128 | struct arcnet_local *lp = dev->priv; | ||
| 129 | struct sk_buff *skb; | ||
| 130 | struct archdr *pkt = pkthdr; | ||
| 131 | int ofs; | ||
| 132 | |||
| 133 | BUGMSG(D_DURING, "it's a raw packet (length=%d)\n", length); | ||
| 134 | |||
| 135 | if (length >= MinTU) | ||
| 136 | ofs = 512 - length; | ||
| 137 | else | ||
| 138 | ofs = 256 - length; | ||
| 139 | |||
| 140 | skb = alloc_skb(length + ARC_HDR_SIZE, GFP_ATOMIC); | ||
| 141 | if (skb == NULL) { | ||
| 142 | BUGMSG(D_NORMAL, "Memory squeeze, dropping packet.\n"); | ||
| 143 | lp->stats.rx_dropped++; | ||
| 144 | return; | ||
| 145 | } | ||
| 146 | skb_put(skb, length + ARC_HDR_SIZE); | ||
| 147 | skb->dev = dev; | ||
| 148 | |||
| 149 | pkt = (struct archdr *) skb->data; | ||
| 150 | |||
| 151 | /* up to sizeof(pkt->soft) has already been copied from the card */ | ||
| 152 | memcpy(pkt, pkthdr, sizeof(struct archdr)); | ||
| 153 | if (length > sizeof(pkt->soft)) | ||
| 154 | lp->hw.copy_from_card(dev, bufnum, ofs + sizeof(pkt->soft), | ||
| 155 | pkt->soft.raw + sizeof(pkt->soft), | ||
| 156 | length - sizeof(pkt->soft)); | ||
| 157 | |||
| 158 | BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx"); | ||
| 159 | |||
| 160 | skb->protocol = type_trans(skb, dev); | ||
| 161 | netif_rx(skb); | ||
| 162 | dev->last_rx = jiffies; | ||
| 163 | } | ||
| 164 | |||
| 165 | |||
| 166 | /* | ||
| 167 | * Create the ARCnet hard/soft headers for RFC1051. | ||
| 168 | */ | ||
| 169 | static int build_header(struct sk_buff *skb, struct net_device *dev, | ||
| 170 | unsigned short type, uint8_t daddr) | ||
| 171 | { | ||
| 172 | struct arcnet_local *lp = dev->priv; | ||
| 173 | int hdr_size = ARC_HDR_SIZE + RFC1051_HDR_SIZE; | ||
| 174 | struct archdr *pkt = (struct archdr *) skb_push(skb, hdr_size); | ||
| 175 | struct arc_rfc1051 *soft = &pkt->soft.rfc1051; | ||
| 176 | |||
| 177 | /* set the protocol ID according to RFC1051 */ | ||
| 178 | switch (type) { | ||
| 179 | case ETH_P_IP: | ||
| 180 | soft->proto = ARC_P_IP_RFC1051; | ||
| 181 | break; | ||
| 182 | case ETH_P_ARP: | ||
| 183 | soft->proto = ARC_P_ARP_RFC1051; | ||
| 184 | break; | ||
| 185 | default: | ||
| 186 | BUGMSG(D_NORMAL, "RFC1051: I don't understand protocol %d (%Xh)\n", | ||
| 187 | type, type); | ||
| 188 | lp->stats.tx_errors++; | ||
| 189 | lp->stats.tx_aborted_errors++; | ||
| 190 | return 0; | ||
| 191 | } | ||
| 192 | |||
| 193 | |||
| 194 | /* | ||
| 195 | * Set the source hardware address. | ||
| 196 | * | ||
| 197 | * This is pretty pointless for most purposes, but it can help in | ||
| 198 | * debugging. ARCnet does not allow us to change the source address in | ||
| 199 | * the actual packet sent) | ||
| 200 | */ | ||
| 201 | pkt->hard.source = *dev->dev_addr; | ||
| 202 | |||
| 203 | /* see linux/net/ethernet/eth.c to see where I got the following */ | ||
| 204 | |||
| 205 | if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) { | ||
| 206 | /* | ||
| 207 | * FIXME: fill in the last byte of the dest ipaddr here to better | ||
| 208 | * comply with RFC1051 in "noarp" mode. | ||
| 209 | */ | ||
| 210 | pkt->hard.dest = 0; | ||
| 211 | return hdr_size; | ||
| 212 | } | ||
| 213 | /* otherwise, just fill it in and go! */ | ||
| 214 | pkt->hard.dest = daddr; | ||
| 215 | |||
| 216 | return hdr_size; /* success */ | ||
| 217 | } | ||
| 218 | |||
| 219 | |||
| 220 | static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, | ||
| 221 | int bufnum) | ||
| 222 | { | ||
| 223 | struct arcnet_local *lp = dev->priv; | ||
| 224 | struct arc_hardware *hard = &pkt->hard; | ||
| 225 | int ofs; | ||
| 226 | |||
| 227 | BUGMSG(D_DURING, "prepare_tx: txbufs=%d/%d/%d\n", | ||
| 228 | lp->next_tx, lp->cur_tx, bufnum); | ||
| 229 | |||
| 230 | length -= ARC_HDR_SIZE; /* hard header is not included in packet length */ | ||
| 231 | |||
| 232 | if (length > XMTU) { | ||
| 233 | /* should never happen! other people already check for this. */ | ||
| 234 | BUGMSG(D_NORMAL, "Bug! prepare_tx with size %d (> %d)\n", | ||
| 235 | length, XMTU); | ||
| 236 | length = XMTU; | ||
| 237 | } | ||
| 238 | if (length > MinTU) { | ||
| 239 | hard->offset[0] = 0; | ||
| 240 | hard->offset[1] = ofs = 512 - length; | ||
| 241 | } else if (length > MTU) { | ||
| 242 | hard->offset[0] = 0; | ||
| 243 | hard->offset[1] = ofs = 512 - length - 3; | ||
| 244 | } else | ||
| 245 | hard->offset[0] = ofs = 256 - length; | ||
| 246 | |||
| 247 | lp->hw.copy_to_card(dev, bufnum, 0, hard, ARC_HDR_SIZE); | ||
| 248 | lp->hw.copy_to_card(dev, bufnum, ofs, &pkt->soft, length); | ||
| 249 | |||
| 250 | lp->lastload_dest = hard->dest; | ||
| 251 | |||
| 252 | return 1; /* done */ | ||
| 253 | } | ||
diff --git a/drivers/net/arcnet/rfc1201.c b/drivers/net/arcnet/rfc1201.c new file mode 100644 index 00000000000..6b6ae4bf3d3 --- /dev/null +++ b/drivers/net/arcnet/rfc1201.c | |||
| @@ -0,0 +1,549 @@ | |||
| 1 | /* | ||
| 2 | * Linux ARCnet driver - RFC1201 (standard) packet encapsulation | ||
| 3 | * | ||
| 4 | * Written 1994-1999 by Avery Pennarun. | ||
| 5 | * Derived from skeleton.c by Donald Becker. | ||
| 6 | * | ||
| 7 | * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) | ||
| 8 | * for sponsoring the further development of this driver. | ||
| 9 | * | ||
| 10 | * ********************** | ||
| 11 | * | ||
| 12 | * The original copyright of skeleton.c was as follows: | ||
| 13 | * | ||
| 14 | * skeleton.c Written 1993 by Donald Becker. | ||
| 15 | * Copyright 1993 United States Government as represented by the | ||
| 16 | * Director, National Security Agency. This software may only be used | ||
| 17 | * and distributed according to the terms of the GNU General Public License as | ||
| 18 | * modified by SRC, incorporated herein by reference. | ||
| 19 | * | ||
| 20 | * ********************** | ||
| 21 | * | ||
| 22 | * For more details, see drivers/net/arcnet.c | ||
| 23 | * | ||
| 24 | * ********************** | ||
| 25 | */ | ||
| 26 | #include <linux/module.h> | ||
| 27 | #include <linux/init.h> | ||
| 28 | #include <linux/if_arp.h> | ||
| 29 | #include <linux/netdevice.h> | ||
| 30 | #include <linux/skbuff.h> | ||
| 31 | #include <linux/arcdevice.h> | ||
| 32 | |||
| 33 | MODULE_LICENSE("GPL"); | ||
| 34 | #define VERSION "arcnet: RFC1201 \"standard\" (`a') encapsulation support loaded.\n" | ||
| 35 | |||
| 36 | |||
| 37 | static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev); | ||
| 38 | static void rx(struct net_device *dev, int bufnum, | ||
| 39 | struct archdr *pkthdr, int length); | ||
| 40 | static int build_header(struct sk_buff *skb, struct net_device *dev, | ||
| 41 | unsigned short type, uint8_t daddr); | ||
| 42 | static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, | ||
| 43 | int bufnum); | ||
| 44 | static int continue_tx(struct net_device *dev, int bufnum); | ||
| 45 | |||
| 46 | struct ArcProto rfc1201_proto = | ||
| 47 | { | ||
| 48 | .suffix = 'a', | ||
| 49 | .mtu = 1500, /* could be more, but some receivers can't handle it... */ | ||
| 50 | .is_ip = 1, /* This is for sending IP and ARP packages */ | ||
| 51 | .rx = rx, | ||
| 52 | .build_header = build_header, | ||
| 53 | .prepare_tx = prepare_tx, | ||
| 54 | .continue_tx = continue_tx, | ||
| 55 | .ack_tx = NULL | ||
| 56 | }; | ||
| 57 | |||
| 58 | |||
| 59 | static int __init arcnet_rfc1201_init(void) | ||
| 60 | { | ||
| 61 | printk(VERSION); | ||
| 62 | |||
| 63 | arc_proto_map[ARC_P_IP] | ||
| 64 | = arc_proto_map[ARC_P_IPV6] | ||
| 65 | = arc_proto_map[ARC_P_ARP] | ||
| 66 | = arc_proto_map[ARC_P_RARP] | ||
| 67 | = arc_proto_map[ARC_P_IPX] | ||
| 68 | = arc_proto_map[ARC_P_NOVELL_EC] | ||
| 69 | = &rfc1201_proto; | ||
| 70 | |||
| 71 | /* if someone else already owns the broadcast, we won't take it */ | ||
| 72 | if (arc_bcast_proto == arc_proto_default) | ||
| 73 | arc_bcast_proto = &rfc1201_proto; | ||
| 74 | |||
| 75 | return 0; | ||
| 76 | } | ||
| 77 | |||
| 78 | static void __exit arcnet_rfc1201_exit(void) | ||
| 79 | { | ||
| 80 | arcnet_unregister_proto(&rfc1201_proto); | ||
| 81 | } | ||
| 82 | |||
| 83 | module_init(arcnet_rfc1201_init); | ||
| 84 | module_exit(arcnet_rfc1201_exit); | ||
| 85 | |||
| 86 | /* | ||
| 87 | * Determine a packet's protocol ID. | ||
| 88 | * | ||
| 89 | * With ARCnet we have to convert everything to Ethernet-style stuff. | ||
| 90 | */ | ||
| 91 | static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev) | ||
| 92 | { | ||
| 93 | struct archdr *pkt = (struct archdr *) skb->data; | ||
| 94 | struct arc_rfc1201 *soft = &pkt->soft.rfc1201; | ||
| 95 | struct arcnet_local *lp = dev->priv; | ||
| 96 | int hdr_size = ARC_HDR_SIZE + RFC1201_HDR_SIZE; | ||
| 97 | |||
| 98 | /* Pull off the arcnet header. */ | ||
| 99 | skb->mac.raw = skb->data; | ||
| 100 | skb_pull(skb, hdr_size); | ||
| 101 | |||
| 102 | if (pkt->hard.dest == 0) | ||
| 103 | skb->pkt_type = PACKET_BROADCAST; | ||
| 104 | else if (dev->flags & IFF_PROMISC) { | ||
| 105 | /* if we're not sending to ourselves :) */ | ||
| 106 | if (pkt->hard.dest != dev->dev_addr[0]) | ||
| 107 | skb->pkt_type = PACKET_OTHERHOST; | ||
| 108 | } | ||
| 109 | /* now return the protocol number */ | ||
| 110 | switch (soft->proto) { | ||
| 111 | case ARC_P_IP: | ||
| 112 | return htons(ETH_P_IP); | ||
| 113 | case ARC_P_IPV6: | ||
| 114 | return htons(ETH_P_IPV6); | ||
| 115 | case ARC_P_ARP: | ||
| 116 | return htons(ETH_P_ARP); | ||
| 117 | case ARC_P_RARP: | ||
| 118 | return htons(ETH_P_RARP); | ||
| 119 | |||
| 120 | case ARC_P_IPX: | ||
| 121 | case ARC_P_NOVELL_EC: | ||
| 122 | return htons(ETH_P_802_3); | ||
| 123 | default: | ||
| 124 | lp->stats.rx_errors++; | ||
| 125 | lp->stats.rx_crc_errors++; | ||
| 126 | return 0; | ||
| 127 | } | ||
| 128 | |||
| 129 | return htons(ETH_P_IP); | ||
| 130 | } | ||
| 131 | |||
| 132 | |||
| 133 | /* packet receiver */ | ||
| 134 | static void rx(struct net_device *dev, int bufnum, | ||
| 135 | struct archdr *pkthdr, int length) | ||
| 136 | { | ||
| 137 | struct arcnet_local *lp = dev->priv; | ||
| 138 | struct sk_buff *skb; | ||
| 139 | struct archdr *pkt = pkthdr; | ||
| 140 | struct arc_rfc1201 *soft = &pkthdr->soft.rfc1201; | ||
| 141 | int saddr = pkt->hard.source, ofs; | ||
| 142 | struct Incoming *in = &lp->rfc1201.incoming[saddr]; | ||
| 143 | |||
| 144 | BUGMSG(D_DURING, "it's an RFC1201 packet (length=%d)\n", length); | ||
| 145 | |||
| 146 | if (length >= MinTU) | ||
| 147 | ofs = 512 - length; | ||
| 148 | else | ||
| 149 | ofs = 256 - length; | ||
| 150 | |||
| 151 | if (soft->split_flag == 0xFF) { /* Exception Packet */ | ||
| 152 | if (length >= 4 + RFC1201_HDR_SIZE) | ||
| 153 | BUGMSG(D_DURING, "compensating for exception packet\n"); | ||
| 154 | else { | ||
| 155 | BUGMSG(D_EXTRA, "short RFC1201 exception packet from %02Xh", | ||
| 156 | saddr); | ||
| 157 | return; | ||
| 158 | } | ||
| 159 | |||
| 160 | /* skip over 4-byte junkola */ | ||
| 161 | length -= 4; | ||
| 162 | ofs += 4; | ||
| 163 | lp->hw.copy_from_card(dev, bufnum, 512 - length, | ||
| 164 | soft, sizeof(pkt->soft)); | ||
| 165 | } | ||
| 166 | if (!soft->split_flag) { /* not split */ | ||
| 167 | BUGMSG(D_RX, "incoming is not split (splitflag=%d)\n", | ||
| 168 | soft->split_flag); | ||
| 169 | |||
| 170 | if (in->skb) { /* already assembling one! */ | ||
| 171 | BUGMSG(D_EXTRA, "aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n", | ||
| 172 | in->sequence, soft->split_flag, soft->sequence); | ||
| 173 | lp->rfc1201.aborted_seq = soft->sequence; | ||
| 174 | dev_kfree_skb_irq(in->skb); | ||
| 175 | lp->stats.rx_errors++; | ||
| 176 | lp->stats.rx_missed_errors++; | ||
| 177 | in->skb = NULL; | ||
| 178 | } | ||
| 179 | in->sequence = soft->sequence; | ||
| 180 | |||
| 181 | skb = alloc_skb(length + ARC_HDR_SIZE, GFP_ATOMIC); | ||
| 182 | if (skb == NULL) { | ||
| 183 | BUGMSG(D_NORMAL, "Memory squeeze, dropping packet.\n"); | ||
| 184 | lp->stats.rx_dropped++; | ||
| 185 | return; | ||
| 186 | } | ||
| 187 | skb_put(skb, length + ARC_HDR_SIZE); | ||
| 188 | skb->dev = dev; | ||
| 189 | |||
| 190 | pkt = (struct archdr *) skb->data; | ||
| 191 | soft = &pkt->soft.rfc1201; | ||
| 192 | |||
| 193 | /* up to sizeof(pkt->soft) has already been copied from the card */ | ||
| 194 | memcpy(pkt, pkthdr, sizeof(struct archdr)); | ||
| 195 | if (length > sizeof(pkt->soft)) | ||
| 196 | lp->hw.copy_from_card(dev, bufnum, ofs + sizeof(pkt->soft), | ||
| 197 | pkt->soft.raw + sizeof(pkt->soft), | ||
| 198 | length - sizeof(pkt->soft)); | ||
| 199 | |||
| 200 | /* | ||
| 201 | * ARP packets have problems when sent from some DOS systems: the | ||
| 202 | * source address is always 0! So we take the hardware source addr | ||
| 203 | * (which is impossible to fumble) and insert it ourselves. | ||
| 204 | */ | ||
| 205 | if (soft->proto == ARC_P_ARP) { | ||
| 206 | struct arphdr *arp = (struct arphdr *) soft->payload; | ||
| 207 | |||
| 208 | /* make sure addresses are the right length */ | ||
| 209 | if (arp->ar_hln == 1 && arp->ar_pln == 4) { | ||
| 210 | uint8_t *cptr = (uint8_t *) arp + sizeof(struct arphdr); | ||
| 211 | |||
| 212 | if (!*cptr) { /* is saddr = 00? */ | ||
| 213 | BUGMSG(D_EXTRA, | ||
| 214 | "ARP source address was 00h, set to %02Xh.\n", | ||
| 215 | saddr); | ||
| 216 | lp->stats.rx_crc_errors++; | ||
| 217 | *cptr = saddr; | ||
| 218 | } else { | ||
| 219 | BUGMSG(D_DURING, "ARP source address (%Xh) is fine.\n", | ||
| 220 | *cptr); | ||
| 221 | } | ||
| 222 | } else { | ||
| 223 | BUGMSG(D_NORMAL, "funny-shaped ARP packet. (%Xh, %Xh)\n", | ||
| 224 | arp->ar_hln, arp->ar_pln); | ||
| 225 | lp->stats.rx_errors++; | ||
| 226 | lp->stats.rx_crc_errors++; | ||
| 227 | } | ||
| 228 | } | ||
| 229 | BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx"); | ||
| 230 | |||
| 231 | skb->protocol = type_trans(skb, dev); | ||
| 232 | netif_rx(skb); | ||
| 233 | dev->last_rx = jiffies; | ||
| 234 | } else { /* split packet */ | ||
| 235 | /* | ||
| 236 | * NOTE: MSDOS ARP packet correction should only need to apply to | ||
| 237 | * unsplit packets, since ARP packets are so short. | ||
| 238 | * | ||
| 239 | * My interpretation of the RFC1201 document is that if a packet is | ||
| 240 | * received out of order, the entire assembly process should be | ||
| 241 | * aborted. | ||
| 242 | * | ||
| 243 | * The RFC also mentions "it is possible for successfully received | ||
| 244 | * packets to be retransmitted." As of 0.40 all previously received | ||
| 245 | * packets are allowed, not just the most recent one. | ||
| 246 | * | ||
| 247 | * We allow multiple assembly processes, one for each ARCnet card | ||
| 248 | * possible on the network. Seems rather like a waste of memory, | ||
| 249 | * but there's no other way to be reliable. | ||
| 250 | */ | ||
| 251 | |||
| 252 | BUGMSG(D_RX, "packet is split (splitflag=%d, seq=%d)\n", | ||
| 253 | soft->split_flag, in->sequence); | ||
| 254 | |||
| 255 | if (in->skb && in->sequence != soft->sequence) { | ||
| 256 | BUGMSG(D_EXTRA, "wrong seq number (saddr=%d, expected=%d, seq=%d, splitflag=%d)\n", | ||
| 257 | saddr, in->sequence, soft->sequence, | ||
| 258 | soft->split_flag); | ||
| 259 | dev_kfree_skb_irq(in->skb); | ||
| 260 | in->skb = NULL; | ||
| 261 | lp->stats.rx_errors++; | ||
| 262 | lp->stats.rx_missed_errors++; | ||
| 263 | in->lastpacket = in->numpackets = 0; | ||
| 264 | } | ||
| 265 | if (soft->split_flag & 1) { /* first packet in split */ | ||
| 266 | BUGMSG(D_RX, "brand new splitpacket (splitflag=%d)\n", | ||
| 267 | soft->split_flag); | ||
| 268 | if (in->skb) { /* already assembling one! */ | ||
| 269 | BUGMSG(D_EXTRA, "aborting previous (seq=%d) assembly " | ||
| 270 | "(splitflag=%d, seq=%d)\n", | ||
| 271 | in->sequence, soft->split_flag, | ||
| 272 | soft->sequence); | ||
| 273 | lp->stats.rx_errors++; | ||
| 274 | lp->stats.rx_missed_errors++; | ||
| 275 | dev_kfree_skb_irq(in->skb); | ||
| 276 | } | ||
| 277 | in->sequence = soft->sequence; | ||
| 278 | in->numpackets = ((unsigned) soft->split_flag >> 1) + 2; | ||
| 279 | in->lastpacket = 1; | ||
| 280 | |||
| 281 | if (in->numpackets > 16) { | ||
| 282 | BUGMSG(D_EXTRA, "incoming packet more than 16 segments; dropping. (splitflag=%d)\n", | ||
| 283 | soft->split_flag); | ||
| 284 | lp->rfc1201.aborted_seq = soft->sequence; | ||
| 285 | lp->stats.rx_errors++; | ||
| 286 | lp->stats.rx_length_errors++; | ||
| 287 | return; | ||
| 288 | } | ||
| 289 | in->skb = skb = alloc_skb(508 * in->numpackets + ARC_HDR_SIZE, | ||
| 290 | GFP_ATOMIC); | ||
| 291 | if (skb == NULL) { | ||
| 292 | BUGMSG(D_NORMAL, "(split) memory squeeze, dropping packet.\n"); | ||
| 293 | lp->rfc1201.aborted_seq = soft->sequence; | ||
| 294 | lp->stats.rx_dropped++; | ||
| 295 | return; | ||
| 296 | } | ||
| 297 | skb->dev = dev; | ||
| 298 | pkt = (struct archdr *) skb->data; | ||
| 299 | soft = &pkt->soft.rfc1201; | ||
| 300 | |||
| 301 | memcpy(pkt, pkthdr, ARC_HDR_SIZE + RFC1201_HDR_SIZE); | ||
| 302 | skb_put(skb, ARC_HDR_SIZE + RFC1201_HDR_SIZE); | ||
| 303 | |||
| 304 | soft->split_flag = 0; /* end result won't be split */ | ||
| 305 | } else { /* not first packet */ | ||
| 306 | int packetnum = ((unsigned) soft->split_flag >> 1) + 1; | ||
| 307 | |||
| 308 | /* | ||
| 309 | * if we're not assembling, there's no point trying to | ||
| 310 | * continue. | ||
| 311 | */ | ||
| 312 | if (!in->skb) { | ||
| 313 | if (lp->rfc1201.aborted_seq != soft->sequence) { | ||
| 314 | BUGMSG(D_EXTRA, "can't continue split without starting " | ||
| 315 | "first! (splitflag=%d, seq=%d, aborted=%d)\n", | ||
| 316 | soft->split_flag, soft->sequence, | ||
| 317 | lp->rfc1201.aborted_seq); | ||
| 318 | lp->stats.rx_errors++; | ||
| 319 | lp->stats.rx_missed_errors++; | ||
| 320 | } | ||
| 321 | return; | ||
| 322 | } | ||
| 323 | in->lastpacket++; | ||
| 324 | if (packetnum != in->lastpacket) { /* not the right flag! */ | ||
| 325 | /* harmless duplicate? ignore. */ | ||
| 326 | if (packetnum <= in->lastpacket - 1) { | ||
| 327 | BUGMSG(D_EXTRA, "duplicate splitpacket ignored! (splitflag=%d)\n", | ||
| 328 | soft->split_flag); | ||
| 329 | lp->stats.rx_errors++; | ||
| 330 | lp->stats.rx_frame_errors++; | ||
| 331 | return; | ||
| 332 | } | ||
| 333 | /* "bad" duplicate, kill reassembly */ | ||
| 334 | BUGMSG(D_EXTRA, "out-of-order splitpacket, reassembly " | ||
| 335 | "(seq=%d) aborted (splitflag=%d, seq=%d)\n", | ||
| 336 | in->sequence, soft->split_flag, soft->sequence); | ||
| 337 | lp->rfc1201.aborted_seq = soft->sequence; | ||
| 338 | dev_kfree_skb_irq(in->skb); | ||
| 339 | in->skb = NULL; | ||
| 340 | lp->stats.rx_errors++; | ||
| 341 | lp->stats.rx_missed_errors++; | ||
| 342 | in->lastpacket = in->numpackets = 0; | ||
| 343 | return; | ||
| 344 | } | ||
| 345 | pkt = (struct archdr *) in->skb->data; | ||
| 346 | soft = &pkt->soft.rfc1201; | ||
| 347 | } | ||
| 348 | |||
| 349 | skb = in->skb; | ||
| 350 | |||
| 351 | lp->hw.copy_from_card(dev, bufnum, ofs + RFC1201_HDR_SIZE, | ||
| 352 | skb->data + skb->len, | ||
| 353 | length - RFC1201_HDR_SIZE); | ||
| 354 | skb_put(skb, length - RFC1201_HDR_SIZE); | ||
| 355 | |||
| 356 | /* are we done? */ | ||
| 357 | if (in->lastpacket == in->numpackets) { | ||
| 358 | in->skb = NULL; | ||
| 359 | in->lastpacket = in->numpackets = 0; | ||
| 360 | |||
| 361 | BUGMSG(D_SKB_SIZE, "skb: received %d bytes from %02X (unsplit)\n", | ||
| 362 | skb->len, pkt->hard.source); | ||
| 363 | BUGMSG(D_SKB_SIZE, "skb: received %d bytes from %02X (split)\n", | ||
| 364 | skb->len, pkt->hard.source); | ||
| 365 | BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx"); | ||
| 366 | |||
| 367 | skb->protocol = type_trans(skb, dev); | ||
| 368 | netif_rx(skb); | ||
| 369 | dev->last_rx = jiffies; | ||
| 370 | } | ||
| 371 | } | ||
| 372 | } | ||
| 373 | |||
| 374 | |||
| 375 | /* Create the ARCnet hard/soft headers for RFC1201. */ | ||
| 376 | static int build_header(struct sk_buff *skb, struct net_device *dev, | ||
| 377 | unsigned short type, uint8_t daddr) | ||
| 378 | { | ||
| 379 | struct arcnet_local *lp = dev->priv; | ||
| 380 | int hdr_size = ARC_HDR_SIZE + RFC1201_HDR_SIZE; | ||
| 381 | struct archdr *pkt = (struct archdr *) skb_push(skb, hdr_size); | ||
| 382 | struct arc_rfc1201 *soft = &pkt->soft.rfc1201; | ||
| 383 | |||
| 384 | /* set the protocol ID according to RFC1201 */ | ||
| 385 | switch (type) { | ||
| 386 | case ETH_P_IP: | ||
| 387 | soft->proto = ARC_P_IP; | ||
| 388 | break; | ||
| 389 | case ETH_P_IPV6: | ||
| 390 | soft->proto = ARC_P_IPV6; | ||
| 391 | break; | ||
| 392 | case ETH_P_ARP: | ||
| 393 | soft->proto = ARC_P_ARP; | ||
| 394 | break; | ||
| 395 | case ETH_P_RARP: | ||
| 396 | soft->proto = ARC_P_RARP; | ||
| 397 | break; | ||
| 398 | case ETH_P_IPX: | ||
| 399 | case ETH_P_802_3: | ||
| 400 | case ETH_P_802_2: | ||
| 401 | soft->proto = ARC_P_IPX; | ||
| 402 | break; | ||
| 403 | case ETH_P_ATALK: | ||
| 404 | soft->proto = ARC_P_ATALK; | ||
| 405 | break; | ||
| 406 | default: | ||
| 407 | BUGMSG(D_NORMAL, "RFC1201: I don't understand protocol %d (%Xh)\n", | ||
| 408 | type, type); | ||
| 409 | lp->stats.tx_errors++; | ||
| 410 | lp->stats.tx_aborted_errors++; | ||
| 411 | return 0; | ||
| 412 | } | ||
| 413 | |||
| 414 | /* | ||
| 415 | * Set the source hardware address. | ||
| 416 | * | ||
| 417 | * This is pretty pointless for most purposes, but it can help in | ||
| 418 | * debugging. ARCnet does not allow us to change the source address in | ||
| 419 | * the actual packet sent) | ||
| 420 | */ | ||
| 421 | pkt->hard.source = *dev->dev_addr; | ||
| 422 | |||
| 423 | soft->sequence = htons(lp->rfc1201.sequence++); | ||
| 424 | soft->split_flag = 0; /* split packets are done elsewhere */ | ||
| 425 | |||
| 426 | /* see linux/net/ethernet/eth.c to see where I got the following */ | ||
| 427 | |||
| 428 | if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) { | ||
| 429 | /* | ||
| 430 | * FIXME: fill in the last byte of the dest ipaddr here to better | ||
| 431 | * comply with RFC1051 in "noarp" mode. For now, always broadcasting | ||
| 432 | * will probably at least get packets sent out :) | ||
| 433 | */ | ||
| 434 | pkt->hard.dest = 0; | ||
| 435 | return hdr_size; | ||
| 436 | } | ||
| 437 | /* otherwise, drop in the dest address */ | ||
| 438 | pkt->hard.dest = daddr; | ||
| 439 | return hdr_size; | ||
| 440 | } | ||
| 441 | |||
| 442 | |||
| 443 | static void load_pkt(struct net_device *dev, struct arc_hardware *hard, | ||
| 444 | struct arc_rfc1201 *soft, int softlen, int bufnum) | ||
| 445 | { | ||
| 446 | struct arcnet_local *lp = dev->priv; | ||
| 447 | int ofs; | ||
| 448 | |||
| 449 | /* assume length <= XMTU: someone should have handled that by now. */ | ||
| 450 | |||
| 451 | if (softlen > MinTU) { | ||
| 452 | hard->offset[0] = 0; | ||
| 453 | hard->offset[1] = ofs = 512 - softlen; | ||
| 454 | } else if (softlen > MTU) { /* exception packet - add an extra header */ | ||
| 455 | struct arc_rfc1201 excsoft; | ||
| 456 | |||
| 457 | excsoft.proto = soft->proto; | ||
| 458 | excsoft.split_flag = 0xff; | ||
| 459 | excsoft.sequence = 0xffff; | ||
| 460 | |||
| 461 | hard->offset[0] = 0; | ||
| 462 | ofs = 512 - softlen; | ||
| 463 | hard->offset[1] = ofs - RFC1201_HDR_SIZE; | ||
| 464 | lp->hw.copy_to_card(dev, bufnum, ofs - RFC1201_HDR_SIZE, | ||
| 465 | &excsoft, RFC1201_HDR_SIZE); | ||
| 466 | } else | ||
| 467 | hard->offset[0] = ofs = 256 - softlen; | ||
| 468 | |||
| 469 | lp->hw.copy_to_card(dev, bufnum, 0, hard, ARC_HDR_SIZE); | ||
| 470 | lp->hw.copy_to_card(dev, bufnum, ofs, soft, softlen); | ||
| 471 | |||
| 472 | lp->lastload_dest = hard->dest; | ||
| 473 | } | ||
| 474 | |||
| 475 | |||
| 476 | static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, | ||
| 477 | int bufnum) | ||
| 478 | { | ||
| 479 | struct arcnet_local *lp = dev->priv; | ||
| 480 | const int maxsegsize = XMTU - RFC1201_HDR_SIZE; | ||
| 481 | struct Outgoing *out; | ||
| 482 | |||
| 483 | |||
| 484 | BUGMSG(D_DURING, "prepare_tx: txbufs=%d/%d/%d\n", | ||
| 485 | lp->next_tx, lp->cur_tx, bufnum); | ||
| 486 | |||
| 487 | length -= ARC_HDR_SIZE; /* hard header is not included in packet length */ | ||
| 488 | pkt->soft.rfc1201.split_flag = 0; | ||
| 489 | |||
| 490 | /* need to do a split packet? */ | ||
| 491 | if (length > XMTU) { | ||
| 492 | out = &lp->outgoing; | ||
| 493 | |||
| 494 | out->length = length - RFC1201_HDR_SIZE; | ||
| 495 | out->dataleft = lp->outgoing.length; | ||
| 496 | out->numsegs = (out->dataleft + maxsegsize - 1) / maxsegsize; | ||
| 497 | out->segnum = 0; | ||
| 498 | |||
| 499 | BUGMSG(D_DURING, "rfc1201 prep_tx: ready for %d-segment split " | ||
| 500 | "(%d bytes, seq=%d)\n", out->numsegs, out->length, | ||
| 501 | pkt->soft.rfc1201.sequence); | ||
| 502 | |||
| 503 | return 0; /* not done */ | ||
| 504 | } | ||
| 505 | /* just load the packet into the buffers and send it off */ | ||
| 506 | load_pkt(dev, &pkt->hard, &pkt->soft.rfc1201, length, bufnum); | ||
| 507 | |||
| 508 | return 1; /* done */ | ||
| 509 | } | ||
| 510 | |||
| 511 | |||
| 512 | static int continue_tx(struct net_device *dev, int bufnum) | ||
| 513 | { | ||
| 514 | struct arcnet_local *lp = dev->priv; | ||
| 515 | struct Outgoing *out = &lp->outgoing; | ||
| 516 | struct arc_hardware *hard = &out->pkt->hard; | ||
| 517 | struct arc_rfc1201 *soft = &out->pkt->soft.rfc1201, *newsoft; | ||
| 518 | int maxsegsize = XMTU - RFC1201_HDR_SIZE; | ||
| 519 | int seglen; | ||
| 520 | |||
| 521 | BUGMSG(D_DURING, | ||
| 522 | "rfc1201 continue_tx: loading segment %d(+1) of %d (seq=%d)\n", | ||
| 523 | out->segnum, out->numsegs, soft->sequence); | ||
| 524 | |||
| 525 | /* the "new" soft header comes right before the data chunk */ | ||
| 526 | newsoft = (struct arc_rfc1201 *) | ||
| 527 | (out->pkt->soft.raw + out->length - out->dataleft); | ||
| 528 | |||
| 529 | if (!out->segnum) /* first packet; newsoft == soft */ | ||
| 530 | newsoft->split_flag = ((out->numsegs - 2) << 1) | 1; | ||
| 531 | else { | ||
| 532 | newsoft->split_flag = out->segnum << 1; | ||
| 533 | newsoft->proto = soft->proto; | ||
| 534 | newsoft->sequence = soft->sequence; | ||
| 535 | } | ||
| 536 | |||
| 537 | seglen = maxsegsize; | ||
| 538 | if (seglen > out->dataleft) | ||
| 539 | seglen = out->dataleft; | ||
| 540 | out->dataleft -= seglen; | ||
| 541 | |||
| 542 | load_pkt(dev, hard, newsoft, seglen + RFC1201_HDR_SIZE, bufnum); | ||
| 543 | |||
| 544 | out->segnum++; | ||
| 545 | if (out->segnum >= out->numsegs) | ||
| 546 | return 1; | ||
| 547 | else | ||
| 548 | return 0; | ||
| 549 | } | ||
