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 52 static long nfEtherID; 53 static int nfEtherIRQ; 54 55 struct nfeth_private { 56 int ethX; 57 }; 58 59 static struct net_device *nfeth_dev[MAX_UNIT]; 60 61 static 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 75 static 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 */ 90 static 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 130 static 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 144 static 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 170 static void nfeth_tx_timeout(struct net_device *dev, unsigned int txqueue) 171 { 172 dev->stats.tx_errors++; 173 netif_wake_queue(dev); 174 } 175 176 static 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 185 static 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 225 static 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 251 static 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 264 module_init(nfeth_init); 265 module_exit(nfeth_cleanup); 266