nfeth.c (6294B)
1/* 2 * atari_nfeth.c - ARAnyM ethernet card driver for GNU/Linux 3 * 4 * Copyright (c) 2005 Milan Jurik, Petr Stehlik of ARAnyM dev team 5 * 6 * Based on ARAnyM driver for FreeMiNT written by Standa Opichal 7 * 8 * This software may be used and distributed according to the terms of 9 * the GNU General Public License (GPL), incorporated herein by reference. 10 */ 11 12#define DRV_VERSION "0.3" 13#define DRV_RELDATE "10/12/2005" 14 15#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 16 17#include <linux/netdevice.h> 18#include <linux/etherdevice.h> 19#include <linux/interrupt.h> 20#include <linux/module.h> 21#include <asm/natfeat.h> 22#include <asm/virtconvert.h> 23 24enum { 25 GET_VERSION = 0,/* no parameters, return NFAPI_VERSION in d0 */ 26 XIF_INTLEVEL, /* no parameters, return Interrupt Level in d0 */ 27 XIF_IRQ, /* acknowledge interrupt from host */ 28 XIF_START, /* (ethX), called on 'ifup', start receiver thread */ 29 XIF_STOP, /* (ethX), called on 'ifdown', stop the thread */ 30 XIF_READLENGTH, /* (ethX), return size of network data block to read */ 31 XIF_READBLOCK, /* (ethX, buffer, size), read block of network data */ 32 XIF_WRITEBLOCK, /* (ethX, buffer, size), write block of network data */ 33 XIF_GET_MAC, /* (ethX, buffer, size), return MAC HW addr in buffer */ 34 XIF_GET_IPHOST, /* (ethX, buffer, size), return IP address of host */ 35 XIF_GET_IPATARI,/* (ethX, buffer, size), return IP address of atari */ 36 XIF_GET_NETMASK /* (ethX, buffer, size), return IP netmask */ 37}; 38 39#define MAX_UNIT 8 40 41/* These identify the driver base version and may not be removed. */ 42static const char version[] = 43 KERN_INFO KBUILD_MODNAME ".c:v" DRV_VERSION " " DRV_RELDATE 44 " S.Opichal, M.Jurik, P.Stehlik\n" 45 KERN_INFO " http://aranym.org/\n"; 46 47MODULE_AUTHOR("Milan Jurik"); 48MODULE_DESCRIPTION("Atari NFeth driver"); 49MODULE_LICENSE("GPL"); 50 51 52static long nfEtherID; 53static int nfEtherIRQ; 54 55struct nfeth_private { 56 int ethX; 57}; 58 59static struct net_device *nfeth_dev[MAX_UNIT]; 60 61static int nfeth_open(struct net_device *dev) 62{ 63 struct nfeth_private *priv = netdev_priv(dev); 64 int res; 65 66 res = nf_call(nfEtherID + XIF_START, priv->ethX); 67 netdev_dbg(dev, "%s: %d\n", __func__, res); 68 69 /* Ready for data */ 70 netif_start_queue(dev); 71 72 return 0; 73} 74 75static int nfeth_stop(struct net_device *dev) 76{ 77 struct nfeth_private *priv = netdev_priv(dev); 78 79 /* No more data */ 80 netif_stop_queue(dev); 81 82 nf_call(nfEtherID + XIF_STOP, priv->ethX); 83 84 return 0; 85} 86 87/* 88 * Read a packet out of the adapter and pass it to the upper layers 89 */ 90static inline void recv_packet(struct net_device *dev) 91{ 92 struct nfeth_private *priv = netdev_priv(dev); 93 unsigned short pktlen; 94 struct sk_buff *skb; 95 96 /* read packet length (excluding 32 bit crc) */ 97 pktlen = nf_call(nfEtherID + XIF_READLENGTH, priv->ethX); 98 99 netdev_dbg(dev, "%s: %u\n", __func__, pktlen); 100 101 if (!pktlen) { 102 netdev_dbg(dev, "%s: pktlen == 0\n", __func__); 103 dev->stats.rx_errors++; 104 return; 105 } 106 107 skb = dev_alloc_skb(pktlen + 2); 108 if (!skb) { 109 netdev_dbg(dev, "%s: out of mem (buf_alloc failed)\n", 110 __func__); 111 dev->stats.rx_dropped++; 112 return; 113 } 114 115 skb->dev = dev; 116 skb_reserve(skb, 2); /* 16 Byte align */ 117 skb_put(skb, pktlen); /* make room */ 118 nf_call(nfEtherID + XIF_READBLOCK, priv->ethX, virt_to_phys(skb->data), 119 pktlen); 120 121 skb->protocol = eth_type_trans(skb, dev); 122 netif_rx(skb); 123 dev->stats.rx_packets++; 124 dev->stats.rx_bytes += pktlen; 125 126 /* and enqueue packet */ 127 return; 128} 129 130static irqreturn_t nfeth_interrupt(int irq, void *dev_id) 131{ 132 int i, m, mask; 133 134 mask = nf_call(nfEtherID + XIF_IRQ, 0); 135 for (i = 0, m = 1; i < MAX_UNIT; m <<= 1, i++) { 136 if (mask & m && nfeth_dev[i]) { 137 recv_packet(nfeth_dev[i]); 138 nf_call(nfEtherID + XIF_IRQ, m); 139 } 140 } 141 return IRQ_HANDLED; 142} 143 144static int nfeth_xmit(struct sk_buff *skb, struct net_device *dev) 145{ 146 unsigned int len; 147 char *data, shortpkt[ETH_ZLEN]; 148 struct nfeth_private *priv = netdev_priv(dev); 149 150 data = skb->data; 151 len = skb->len; 152 if (len < ETH_ZLEN) { 153 memset(shortpkt, 0, ETH_ZLEN); 154 memcpy(shortpkt, data, len); 155 data = shortpkt; 156 len = ETH_ZLEN; 157 } 158 159 netdev_dbg(dev, "%s: send %u bytes\n", __func__, len); 160 nf_call(nfEtherID + XIF_WRITEBLOCK, priv->ethX, virt_to_phys(data), 161 len); 162 163 dev->stats.tx_packets++; 164 dev->stats.tx_bytes += len; 165 166 dev_kfree_skb(skb); 167 return 0; 168} 169 170static void nfeth_tx_timeout(struct net_device *dev, unsigned int txqueue) 171{ 172 dev->stats.tx_errors++; 173 netif_wake_queue(dev); 174} 175 176static const struct net_device_ops nfeth_netdev_ops = { 177 .ndo_open = nfeth_open, 178 .ndo_stop = nfeth_stop, 179 .ndo_start_xmit = nfeth_xmit, 180 .ndo_tx_timeout = nfeth_tx_timeout, 181 .ndo_validate_addr = eth_validate_addr, 182 .ndo_set_mac_address = eth_mac_addr, 183}; 184 185static struct net_device * __init nfeth_probe(int unit) 186{ 187 struct net_device *dev; 188 struct nfeth_private *priv; 189 char mac[ETH_ALEN], host_ip[32], local_ip[32]; 190 int err; 191 192 if (!nf_call(nfEtherID + XIF_GET_MAC, unit, virt_to_phys(mac), 193 ETH_ALEN)) 194 return NULL; 195 196 dev = alloc_etherdev(sizeof(struct nfeth_private)); 197 if (!dev) 198 return NULL; 199 200 dev->irq = nfEtherIRQ; 201 dev->netdev_ops = &nfeth_netdev_ops; 202 203 eth_hw_addr_set(dev, mac); 204 205 priv = netdev_priv(dev); 206 priv->ethX = unit; 207 208 err = register_netdev(dev); 209 if (err) { 210 free_netdev(dev); 211 return NULL; 212 } 213 214 nf_call(nfEtherID + XIF_GET_IPHOST, unit, 215 virt_to_phys(host_ip), sizeof(host_ip)); 216 nf_call(nfEtherID + XIF_GET_IPATARI, unit, 217 virt_to_phys(local_ip), sizeof(local_ip)); 218 219 netdev_info(dev, KBUILD_MODNAME " addr:%s (%s) HWaddr:%pM\n", host_ip, 220 local_ip, mac); 221 222 return dev; 223} 224 225static int __init nfeth_init(void) 226{ 227 long ver; 228 int error, i; 229 230 nfEtherID = nf_get_id("ETHERNET"); 231 if (!nfEtherID) 232 return -ENODEV; 233 234 ver = nf_call(nfEtherID + GET_VERSION); 235 pr_info("API %lu\n", ver); 236 237 nfEtherIRQ = nf_call(nfEtherID + XIF_INTLEVEL); 238 error = request_irq(nfEtherIRQ, nfeth_interrupt, IRQF_SHARED, 239 "eth emu", nfeth_interrupt); 240 if (error) { 241 pr_err("request for irq %d failed %d", nfEtherIRQ, error); 242 return error; 243 } 244 245 for (i = 0; i < MAX_UNIT; i++) 246 nfeth_dev[i] = nfeth_probe(i); 247 248 return 0; 249} 250 251static void __exit nfeth_cleanup(void) 252{ 253 int i; 254 255 for (i = 0; i < MAX_UNIT; i++) { 256 if (nfeth_dev[i]) { 257 unregister_netdev(nfeth_dev[i]); 258 free_netdev(nfeth_dev[i]); 259 } 260 } 261 free_irq(nfEtherIRQ, nfeth_interrupt); 262} 263 264module_init(nfeth_init); 265module_exit(nfeth_cleanup);