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