19cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik/* 29cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik * atari_nfeth.c - ARAnyM ethernet card driver for GNU/Linux 39cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik * 49cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik * Copyright (c) 2005 Milan Jurik, Petr Stehlik of ARAnyM dev team 59cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik * 69cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik * Based on ARAnyM driver for FreeMiNT written by Standa Opichal 79cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik * 89cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik * This software may be used and distributed according to the terms of 99cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik * the GNU General Public License (GPL), incorporated herein by reference. 109cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik */ 119cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 129cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik#define DRV_VERSION "0.3" 139cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik#define DRV_RELDATE "10/12/2005" 149cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 159cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 169cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 179cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik#include <linux/netdevice.h> 189cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik#include <linux/etherdevice.h> 19ac752277961c0aba08ba7b33e7c93a56f711cef9Geert Uytterhoeven#include <linux/interrupt.h> 209cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik#include <linux/module.h> 219cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik#include <asm/natfeat.h> 229cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik#include <asm/virtconvert.h> 239cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 249cd7b148312f6971f37cfac6a490688286bd1522Milan Jurikenum { 259cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik GET_VERSION = 0,/* no parameters, return NFAPI_VERSION in d0 */ 269cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik XIF_INTLEVEL, /* no parameters, return Interrupt Level in d0 */ 279cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik XIF_IRQ, /* acknowledge interrupt from host */ 289cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik XIF_START, /* (ethX), called on 'ifup', start receiver thread */ 299cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik XIF_STOP, /* (ethX), called on 'ifdown', stop the thread */ 309cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik XIF_READLENGTH, /* (ethX), return size of network data block to read */ 319cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik XIF_READBLOCK, /* (ethX, buffer, size), read block of network data */ 329cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik XIF_WRITEBLOCK, /* (ethX, buffer, size), write block of network data */ 339cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik XIF_GET_MAC, /* (ethX, buffer, size), return MAC HW addr in buffer */ 349cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik XIF_GET_IPHOST, /* (ethX, buffer, size), return IP address of host */ 359cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik XIF_GET_IPATARI,/* (ethX, buffer, size), return IP address of atari */ 369cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik XIF_GET_NETMASK /* (ethX, buffer, size), return IP netmask */ 379cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik}; 389cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 399cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik#define MAX_UNIT 8 409cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 419cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik/* These identify the driver base version and may not be removed. */ 42b881bc469bdbdcca60e75047885509eb9886d3a2Greg Kroah-Hartmanstatic const char version[] = 439cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik KERN_INFO KBUILD_MODNAME ".c:v" DRV_VERSION " " DRV_RELDATE 449cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik " S.Opichal, M.Jurik, P.Stehlik\n" 459cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik KERN_INFO " http://aranym.org/\n"; 469cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 479cd7b148312f6971f37cfac6a490688286bd1522Milan JurikMODULE_AUTHOR("Milan Jurik"); 489cd7b148312f6971f37cfac6a490688286bd1522Milan JurikMODULE_DESCRIPTION("Atari NFeth driver"); 499cd7b148312f6971f37cfac6a490688286bd1522Milan JurikMODULE_LICENSE("GPL"); 509cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik/* 519cd7b148312f6971f37cfac6a490688286bd1522Milan JurikMODULE_PARM(nfeth_debug, "i"); 529cd7b148312f6971f37cfac6a490688286bd1522Milan JurikMODULE_PARM_DESC(nfeth_debug, "nfeth_debug level (1-2)"); 539cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik*/ 549cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 559cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 569cd7b148312f6971f37cfac6a490688286bd1522Milan Jurikstatic long nfEtherID; 579cd7b148312f6971f37cfac6a490688286bd1522Milan Jurikstatic int nfEtherIRQ; 589cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 599cd7b148312f6971f37cfac6a490688286bd1522Milan Jurikstruct nfeth_private { 609cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik int ethX; 619cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik}; 629cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 639cd7b148312f6971f37cfac6a490688286bd1522Milan Jurikstatic struct net_device *nfeth_dev[MAX_UNIT]; 649cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 659cd7b148312f6971f37cfac6a490688286bd1522Milan Jurikstatic int nfeth_open(struct net_device *dev) 669cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik{ 679cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik struct nfeth_private *priv = netdev_priv(dev); 689cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik int res; 699cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 709cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik res = nf_call(nfEtherID + XIF_START, priv->ethX); 719cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik netdev_dbg(dev, "%s: %d\n", __func__, res); 729cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 739cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik /* Ready for data */ 749cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik netif_start_queue(dev); 759cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 769cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik return 0; 779cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik} 789cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 799cd7b148312f6971f37cfac6a490688286bd1522Milan Jurikstatic int nfeth_stop(struct net_device *dev) 809cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik{ 819cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik struct nfeth_private *priv = netdev_priv(dev); 829cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 839cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik /* No more data */ 849cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik netif_stop_queue(dev); 859cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 869cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik nf_call(nfEtherID + XIF_STOP, priv->ethX); 879cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 889cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik return 0; 899cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik} 909cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 919cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik/* 929cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik * Read a packet out of the adapter and pass it to the upper layers 939cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik */ 949cd7b148312f6971f37cfac6a490688286bd1522Milan Jurikstatic inline void recv_packet(struct net_device *dev) 959cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik{ 969cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik struct nfeth_private *priv = netdev_priv(dev); 979cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik unsigned short pktlen; 989cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik struct sk_buff *skb; 999cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 1009cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik /* read packet length (excluding 32 bit crc) */ 1019cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik pktlen = nf_call(nfEtherID + XIF_READLENGTH, priv->ethX); 1029cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 1039cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik netdev_dbg(dev, "%s: %u\n", __func__, pktlen); 1049cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 1059cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik if (!pktlen) { 1069cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik netdev_dbg(dev, "%s: pktlen == 0\n", __func__); 1079cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik dev->stats.rx_errors++; 1089cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik return; 1099cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik } 1109cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 1119cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik skb = dev_alloc_skb(pktlen + 2); 1129cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik if (!skb) { 1139cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik netdev_dbg(dev, "%s: out of mem (buf_alloc failed)\n", 1149cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik __func__); 1159cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik dev->stats.rx_dropped++; 1169cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik return; 1179cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik } 1189cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 1199cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik skb->dev = dev; 1209cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik skb_reserve(skb, 2); /* 16 Byte align */ 1219cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik skb_put(skb, pktlen); /* make room */ 1229cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik nf_call(nfEtherID + XIF_READBLOCK, priv->ethX, virt_to_phys(skb->data), 1239cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik pktlen); 1249cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 1259cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik skb->protocol = eth_type_trans(skb, dev); 1269cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik netif_rx(skb); 1279cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik dev->last_rx = jiffies; 1289cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik dev->stats.rx_packets++; 1299cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik dev->stats.rx_bytes += pktlen; 1309cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 1319cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik /* and enqueue packet */ 1329cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik return; 1339cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik} 1349cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 1359cd7b148312f6971f37cfac6a490688286bd1522Milan Jurikstatic irqreturn_t nfeth_interrupt(int irq, void *dev_id) 1369cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik{ 1379cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik int i, m, mask; 1389cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 1399cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik mask = nf_call(nfEtherID + XIF_IRQ, 0); 1409cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik for (i = 0, m = 1; i < MAX_UNIT; m <<= 1, i++) { 1419cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik if (mask & m && nfeth_dev[i]) { 1429cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik recv_packet(nfeth_dev[i]); 1439cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik nf_call(nfEtherID + XIF_IRQ, m); 1449cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik } 1459cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik } 1469cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik return IRQ_HANDLED; 1479cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik} 1489cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 1499cd7b148312f6971f37cfac6a490688286bd1522Milan Jurikstatic int nfeth_xmit(struct sk_buff *skb, struct net_device *dev) 1509cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik{ 1519cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik unsigned int len; 1529cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik char *data, shortpkt[ETH_ZLEN]; 1539cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik struct nfeth_private *priv = netdev_priv(dev); 1549cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 1559cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik data = skb->data; 1569cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik len = skb->len; 1579cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik if (len < ETH_ZLEN) { 1589cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik memset(shortpkt, 0, ETH_ZLEN); 1599cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik memcpy(shortpkt, data, len); 1609cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik data = shortpkt; 1619cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik len = ETH_ZLEN; 1629cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik } 1639cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 1649cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik netdev_dbg(dev, "%s: send %u bytes\n", __func__, len); 1659cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik nf_call(nfEtherID + XIF_WRITEBLOCK, priv->ethX, virt_to_phys(data), 1669cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik len); 1679cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 1689cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik dev->stats.tx_packets++; 1699cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik dev->stats.tx_bytes += len; 1709cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 1719cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik dev_kfree_skb(skb); 1729cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik return 0; 1739cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik} 1749cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 1759cd7b148312f6971f37cfac6a490688286bd1522Milan Jurikstatic void nfeth_tx_timeout(struct net_device *dev) 1769cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik{ 1779cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik dev->stats.tx_errors++; 1789cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik netif_wake_queue(dev); 1799cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik} 1809cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 1819cd7b148312f6971f37cfac6a490688286bd1522Milan Jurikstatic const struct net_device_ops nfeth_netdev_ops = { 1829cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik .ndo_open = nfeth_open, 1839cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik .ndo_stop = nfeth_stop, 1849cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik .ndo_start_xmit = nfeth_xmit, 1859cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik .ndo_tx_timeout = nfeth_tx_timeout, 1869cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik .ndo_validate_addr = eth_validate_addr, 1879cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik .ndo_change_mtu = eth_change_mtu, 1889cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik .ndo_set_mac_address = eth_mac_addr, 1899cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik}; 1909cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 1919cd7b148312f6971f37cfac6a490688286bd1522Milan Jurikstatic struct net_device * __init nfeth_probe(int unit) 1929cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik{ 1939cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik struct net_device *dev; 1949cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik struct nfeth_private *priv; 1959cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik char mac[ETH_ALEN], host_ip[32], local_ip[32]; 1969cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik int err; 1979cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 19855490050df0f5d82ce070be11351c65f7696101cGeert Uytterhoeven if (!nf_call(nfEtherID + XIF_GET_MAC, unit, virt_to_phys(mac), 19955490050df0f5d82ce070be11351c65f7696101cGeert Uytterhoeven ETH_ALEN)) 2009cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik return NULL; 2019cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 2029cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik dev = alloc_etherdev(sizeof(struct nfeth_private)); 2039cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik if (!dev) 2049cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik return NULL; 2059cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 2069cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik dev->irq = nfEtherIRQ; 2079cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik dev->netdev_ops = &nfeth_netdev_ops; 2089cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 2099cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik memcpy(dev->dev_addr, mac, ETH_ALEN); 2109cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 2119cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik priv = netdev_priv(dev); 2129cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik priv->ethX = unit; 2139cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 2149cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik err = register_netdev(dev); 2159cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik if (err) { 2169cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik free_netdev(dev); 2179cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik return NULL; 2189cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik } 2199cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 2209cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik nf_call(nfEtherID + XIF_GET_IPHOST, unit, 22155490050df0f5d82ce070be11351c65f7696101cGeert Uytterhoeven virt_to_phys(host_ip), sizeof(host_ip)); 2229cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik nf_call(nfEtherID + XIF_GET_IPATARI, unit, 22355490050df0f5d82ce070be11351c65f7696101cGeert Uytterhoeven virt_to_phys(local_ip), sizeof(local_ip)); 2249cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 2259cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik netdev_info(dev, KBUILD_MODNAME " addr:%s (%s) HWaddr:%pM\n", host_ip, 2269cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik local_ip, mac); 2279cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 2289cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik return dev; 2299cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik} 2309cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 2319cd7b148312f6971f37cfac6a490688286bd1522Milan Jurikstatic int __init nfeth_init(void) 2329cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik{ 2339cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik long ver; 2349cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik int error, i; 2359cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 2369cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik nfEtherID = nf_get_id("ETHERNET"); 2379cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik if (!nfEtherID) 2389cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik return -ENODEV; 2399cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 2409cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik ver = nf_call(nfEtherID + GET_VERSION); 2419cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik pr_info("API %lu\n", ver); 2429cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 2439cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik nfEtherIRQ = nf_call(nfEtherID + XIF_INTLEVEL); 2449cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik error = request_irq(nfEtherIRQ, nfeth_interrupt, IRQF_SHARED, 2459cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik "eth emu", nfeth_interrupt); 2469cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik if (error) { 2479cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik pr_err("request for irq %d failed %d", nfEtherIRQ, error); 2489cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik return error; 2499cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik } 2509cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 2519cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik for (i = 0; i < MAX_UNIT; i++) 2529cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik nfeth_dev[i] = nfeth_probe(i); 2539cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 2549cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik return 0; 2559cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik} 2569cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 2579cd7b148312f6971f37cfac6a490688286bd1522Milan Jurikstatic void __exit nfeth_cleanup(void) 2589cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik{ 2599cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik int i; 2609cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 2619cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik for (i = 0; i < MAX_UNIT; i++) { 2629cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik if (nfeth_dev[i]) { 2639cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik unregister_netdev(nfeth_dev[0]); 2649cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik free_netdev(nfeth_dev[0]); 2659cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik } 2669cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik } 2679cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik free_irq(nfEtherIRQ, nfeth_interrupt); 2689cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik} 2699cd7b148312f6971f37cfac6a490688286bd1522Milan Jurik 2709cd7b148312f6971f37cfac6a490688286bd1522Milan Jurikmodule_init(nfeth_init); 2719cd7b148312f6971f37cfac6a490688286bd1522Milan Jurikmodule_exit(nfeth_cleanup); 272