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 24 enum { 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. */ 42 static 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 47 MODULE_AUTHOR("Milan Jurik"); 48 MODULE_DESCRIPTION("Atari NFeth driver"); 49 MODULE_LICENSE("GPL"); 50 /* 51 MODULE_PARM(nfeth_debug, "i"); 52 MODULE_PARM_DESC(nfeth_debug, "nfeth_debug level (1-2)"); 53 */ 54 55 56 static long nfEtherID; 57 static int nfEtherIRQ; 58 59 struct nfeth_private { 60 int ethX; 61 }; 62 63 static struct net_device *nfeth_dev[MAX_UNIT]; 64 65 static int nfeth_open(struct net_device *dev) 66 { 67 struct nfeth_private *priv = netdev_priv(dev); 68 int res; 69 70 res = nf_call(nfEtherID + XIF_START, priv->ethX); 71 netdev_dbg(dev, "%s: %d\n", __func__, res); 72 73 /* Ready for data */ 74 netif_start_queue(dev); 75 76 return 0; 77 } 78 79 static int nfeth_stop(struct net_device *dev) 80 { 81 struct nfeth_private *priv = netdev_priv(dev); 82 83 /* No more data */ 84 netif_stop_queue(dev); 85 86 nf_call(nfEtherID + XIF_STOP, priv->ethX); 87 88 return 0; 89 } 90 91 /* 92 * Read a packet out of the adapter and pass it to the upper layers 93 */ 94 static inline void recv_packet(struct net_device *dev) 95 { 96 struct nfeth_private *priv = netdev_priv(dev); 97 unsigned short pktlen; 98 struct sk_buff *skb; 99 100 /* read packet length (excluding 32 bit crc) */ 101 pktlen = nf_call(nfEtherID + XIF_READLENGTH, priv->ethX); 102 103 netdev_dbg(dev, "%s: %u\n", __func__, pktlen); 104 105 if (!pktlen) { 106 netdev_dbg(dev, "%s: pktlen == 0\n", __func__); 107 dev->stats.rx_errors++; 108 return; 109 } 110 111 skb = dev_alloc_skb(pktlen + 2); 112 if (!skb) { 113 netdev_dbg(dev, "%s: out of mem (buf_alloc failed)\n", 114 __func__); 115 dev->stats.rx_dropped++; 116 return; 117 } 118 119 skb->dev = dev; 120 skb_reserve(skb, 2); /* 16 Byte align */ 121 skb_put(skb, pktlen); /* make room */ 122 nf_call(nfEtherID + XIF_READBLOCK, priv->ethX, virt_to_phys(skb->data), 123 pktlen); 124 125 skb->protocol = eth_type_trans(skb, dev); 126 netif_rx(skb); 127 dev->last_rx = jiffies; 128 dev->stats.rx_packets++; 129 dev->stats.rx_bytes += pktlen; 130 131 /* and enqueue packet */ 132 return; 133 } 134 135 static irqreturn_t nfeth_interrupt(int irq, void *dev_id) 136 { 137 int i, m, mask; 138 139 mask = nf_call(nfEtherID + XIF_IRQ, 0); 140 for (i = 0, m = 1; i < MAX_UNIT; m <<= 1, i++) { 141 if (mask & m && nfeth_dev[i]) { 142 recv_packet(nfeth_dev[i]); 143 nf_call(nfEtherID + XIF_IRQ, m); 144 } 145 } 146 return IRQ_HANDLED; 147 } 148 149 static int nfeth_xmit(struct sk_buff *skb, struct net_device *dev) 150 { 151 unsigned int len; 152 char *data, shortpkt[ETH_ZLEN]; 153 struct nfeth_private *priv = netdev_priv(dev); 154 155 data = skb->data; 156 len = skb->len; 157 if (len < ETH_ZLEN) { 158 memset(shortpkt, 0, ETH_ZLEN); 159 memcpy(shortpkt, data, len); 160 data = shortpkt; 161 len = ETH_ZLEN; 162 } 163 164 netdev_dbg(dev, "%s: send %u bytes\n", __func__, len); 165 nf_call(nfEtherID + XIF_WRITEBLOCK, priv->ethX, virt_to_phys(data), 166 len); 167 168 dev->stats.tx_packets++; 169 dev->stats.tx_bytes += len; 170 171 dev_kfree_skb(skb); 172 return 0; 173 } 174 175 static void nfeth_tx_timeout(struct net_device *dev) 176 { 177 dev->stats.tx_errors++; 178 netif_wake_queue(dev); 179 } 180 181 static const struct net_device_ops nfeth_netdev_ops = { 182 .ndo_open = nfeth_open, 183 .ndo_stop = nfeth_stop, 184 .ndo_start_xmit = nfeth_xmit, 185 .ndo_tx_timeout = nfeth_tx_timeout, 186 .ndo_validate_addr = eth_validate_addr, 187 .ndo_change_mtu = eth_change_mtu, 188 .ndo_set_mac_address = eth_mac_addr, 189 }; 190 191 static struct net_device * __init nfeth_probe(int unit) 192 { 193 struct net_device *dev; 194 struct nfeth_private *priv; 195 char mac[ETH_ALEN], host_ip[32], local_ip[32]; 196 int err; 197 198 if (!nf_call(nfEtherID + XIF_GET_MAC, unit, virt_to_phys(mac), 199 ETH_ALEN)) 200 return NULL; 201 202 dev = alloc_etherdev(sizeof(struct nfeth_private)); 203 if (!dev) 204 return NULL; 205 206 dev->irq = nfEtherIRQ; 207 dev->netdev_ops = &nfeth_netdev_ops; 208 209 memcpy(dev->dev_addr, mac, ETH_ALEN); 210 211 priv = netdev_priv(dev); 212 priv->ethX = unit; 213 214 err = register_netdev(dev); 215 if (err) { 216 free_netdev(dev); 217 return NULL; 218 } 219 220 nf_call(nfEtherID + XIF_GET_IPHOST, unit, 221 virt_to_phys(host_ip), sizeof(host_ip)); 222 nf_call(nfEtherID + XIF_GET_IPATARI, unit, 223 virt_to_phys(local_ip), sizeof(local_ip)); 224 225 netdev_info(dev, KBUILD_MODNAME " addr:%s (%s) HWaddr:%pM\n", host_ip, 226 local_ip, mac); 227 228 return dev; 229 } 230 231 static int __init nfeth_init(void) 232 { 233 long ver; 234 int error, i; 235 236 nfEtherID = nf_get_id("ETHERNET"); 237 if (!nfEtherID) 238 return -ENODEV; 239 240 ver = nf_call(nfEtherID + GET_VERSION); 241 pr_info("API %lu\n", ver); 242 243 nfEtherIRQ = nf_call(nfEtherID + XIF_INTLEVEL); 244 error = request_irq(nfEtherIRQ, nfeth_interrupt, IRQF_SHARED, 245 "eth emu", nfeth_interrupt); 246 if (error) { 247 pr_err("request for irq %d failed %d", nfEtherIRQ, error); 248 return error; 249 } 250 251 for (i = 0; i < MAX_UNIT; i++) 252 nfeth_dev[i] = nfeth_probe(i); 253 254 return 0; 255 } 256 257 static void __exit nfeth_cleanup(void) 258 { 259 int i; 260 261 for (i = 0; i < MAX_UNIT; i++) { 262 if (nfeth_dev[i]) { 263 unregister_netdev(nfeth_dev[0]); 264 free_netdev(nfeth_dev[0]); 265 } 266 } 267 free_irq(nfEtherIRQ, nfeth_interrupt); 268 } 269 270 module_init(nfeth_init); 271 module_exit(nfeth_cleanup); 272