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->stats.rx_packets++; 128 dev->stats.rx_bytes += pktlen; 129 130 /* and enqueue packet */ 131 return; 132 } 133 134 static irqreturn_t nfeth_interrupt(int irq, void *dev_id) 135 { 136 int i, m, mask; 137 138 mask = nf_call(nfEtherID + XIF_IRQ, 0); 139 for (i = 0, m = 1; i < MAX_UNIT; m <<= 1, i++) { 140 if (mask & m && nfeth_dev[i]) { 141 recv_packet(nfeth_dev[i]); 142 nf_call(nfEtherID + XIF_IRQ, m); 143 } 144 } 145 return IRQ_HANDLED; 146 } 147 148 static int nfeth_xmit(struct sk_buff *skb, struct net_device *dev) 149 { 150 unsigned int len; 151 char *data, shortpkt[ETH_ZLEN]; 152 struct nfeth_private *priv = netdev_priv(dev); 153 154 data = skb->data; 155 len = skb->len; 156 if (len < ETH_ZLEN) { 157 memset(shortpkt, 0, ETH_ZLEN); 158 memcpy(shortpkt, data, len); 159 data = shortpkt; 160 len = ETH_ZLEN; 161 } 162 163 netdev_dbg(dev, "%s: send %u bytes\n", __func__, len); 164 nf_call(nfEtherID + XIF_WRITEBLOCK, priv->ethX, virt_to_phys(data), 165 len); 166 167 dev->stats.tx_packets++; 168 dev->stats.tx_bytes += len; 169 170 dev_kfree_skb(skb); 171 return 0; 172 } 173 174 static void nfeth_tx_timeout(struct net_device *dev) 175 { 176 dev->stats.tx_errors++; 177 netif_wake_queue(dev); 178 } 179 180 static const struct net_device_ops nfeth_netdev_ops = { 181 .ndo_open = nfeth_open, 182 .ndo_stop = nfeth_stop, 183 .ndo_start_xmit = nfeth_xmit, 184 .ndo_tx_timeout = nfeth_tx_timeout, 185 .ndo_validate_addr = eth_validate_addr, 186 .ndo_set_mac_address = eth_mac_addr, 187 }; 188 189 static struct net_device * __init nfeth_probe(int unit) 190 { 191 struct net_device *dev; 192 struct nfeth_private *priv; 193 char mac[ETH_ALEN], host_ip[32], local_ip[32]; 194 int err; 195 196 if (!nf_call(nfEtherID + XIF_GET_MAC, unit, virt_to_phys(mac), 197 ETH_ALEN)) 198 return NULL; 199 200 dev = alloc_etherdev(sizeof(struct nfeth_private)); 201 if (!dev) 202 return NULL; 203 204 dev->irq = nfEtherIRQ; 205 dev->netdev_ops = &nfeth_netdev_ops; 206 207 memcpy(dev->dev_addr, mac, ETH_ALEN); 208 209 priv = netdev_priv(dev); 210 priv->ethX = unit; 211 212 err = register_netdev(dev); 213 if (err) { 214 free_netdev(dev); 215 return NULL; 216 } 217 218 nf_call(nfEtherID + XIF_GET_IPHOST, unit, 219 virt_to_phys(host_ip), sizeof(host_ip)); 220 nf_call(nfEtherID + XIF_GET_IPATARI, unit, 221 virt_to_phys(local_ip), sizeof(local_ip)); 222 223 netdev_info(dev, KBUILD_MODNAME " addr:%s (%s) HWaddr:%pM\n", host_ip, 224 local_ip, mac); 225 226 return dev; 227 } 228 229 static int __init nfeth_init(void) 230 { 231 long ver; 232 int error, i; 233 234 nfEtherID = nf_get_id("ETHERNET"); 235 if (!nfEtherID) 236 return -ENODEV; 237 238 ver = nf_call(nfEtherID + GET_VERSION); 239 pr_info("API %lu\n", ver); 240 241 nfEtherIRQ = nf_call(nfEtherID + XIF_INTLEVEL); 242 error = request_irq(nfEtherIRQ, nfeth_interrupt, IRQF_SHARED, 243 "eth emu", nfeth_interrupt); 244 if (error) { 245 pr_err("request for irq %d failed %d", nfEtherIRQ, error); 246 return error; 247 } 248 249 for (i = 0; i < MAX_UNIT; i++) 250 nfeth_dev[i] = nfeth_probe(i); 251 252 return 0; 253 } 254 255 static void __exit nfeth_cleanup(void) 256 { 257 int i; 258 259 for (i = 0; i < MAX_UNIT; i++) { 260 if (nfeth_dev[i]) { 261 unregister_netdev(nfeth_dev[0]); 262 free_netdev(nfeth_dev[0]); 263 } 264 } 265 free_irq(nfEtherIRQ, nfeth_interrupt); 266 } 267 268 module_init(nfeth_init); 269 module_exit(nfeth_cleanup); 270