linux/arch/m68k/emu/nfeth.c
<<
>>
Prefs
   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/*
  51MODULE_PARM(nfeth_debug, "i");
  52MODULE_PARM_DESC(nfeth_debug, "nfeth_debug level (1-2)");
  53*/
  54
  55
  56static long nfEtherID;
  57static int nfEtherIRQ;
  58
  59struct nfeth_private {
  60        int ethX;
  61};
  62
  63static struct net_device *nfeth_dev[MAX_UNIT];
  64
  65static 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
  79static 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 */
  94static 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
 134static 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
 148static 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
 174static void nfeth_tx_timeout(struct net_device *dev)
 175{
 176        dev->stats.tx_errors++;
 177        netif_wake_queue(dev);
 178}
 179
 180static 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_change_mtu         = eth_change_mtu,
 187        .ndo_set_mac_address    = eth_mac_addr,
 188};
 189
 190static struct net_device * __init nfeth_probe(int unit)
 191{
 192        struct net_device *dev;
 193        struct nfeth_private *priv;
 194        char mac[ETH_ALEN], host_ip[32], local_ip[32];
 195        int err;
 196
 197        if (!nf_call(nfEtherID + XIF_GET_MAC, unit, mac, 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                host_ip, sizeof(host_ip));
 220        nf_call(nfEtherID + XIF_GET_IPATARI, unit,
 221                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
 229static 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
 255static 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
 268module_init(nfeth_init);
 269module_exit(nfeth_cleanup);
 270