linux-bk/drivers/net/atari_bionet.c
<<
>>
Prefs
   1/* bionet.c     BioNet-100 device driver for linux68k.
   2 *
   3 * Version:     @(#)bionet.c    1.0     02/06/96
   4 *
   5 * Author:      Hartmut Laue <laue@ifk-mp.uni-kiel.de>
   6 * and          Torsten Narjes <narjes@ifk-mp.uni-kiel.de>
   7 *
   8 * Little adaptions for integration into pl7 by Roman Hodek
   9 *
  10 * Some changes in bionet_poll_rx by Karl-Heinz Lohner
  11 *
  12        What is it ?
  13        ------------
  14        This driver controls the BIONET-100 LAN-Adapter which connects
  15        an ATARI ST/TT via the ACSI-port to an Ethernet-based network.
  16
  17        This version can be compiled as a loadable module (See the
  18        compile command at the bottom of this file).
  19        At load time, you can optionally set the debugging level and the
  20        fastest response time on the command line of 'insmod'.
  21
  22        'bionet_debug'
  23                controls the amount of diagnostic messages:
  24          0  : no messages
  25          >0 : see code for meaning of printed messages
  26
  27        'bionet_min_poll_time' (always >=1)
  28                gives the time (in jiffies) between polls. Low values
  29                increase the system load (beware!)
  30
  31        When loaded, a net device with the name 'bio0' becomes available,
  32        which can be controlled with the usual 'ifconfig' command.
  33
  34        It is possible to compile this driver into the kernel like other
  35        (net) drivers. For this purpose, some source files (e.g. config-files
  36        makefiles, Space.c) must be changed accordingly. (You may refer to
  37        other drivers how to do it.) In this case, the device will be detected
  38        at boot time and (probably) appear as 'eth0'.
  39
  40        This code is based on several sources:
  41        - The driver code for a parallel port ethernet adapter by
  42          Donald Becker (see file 'atp.c' from the PC linux distribution)
  43        - The ACSI code by Roman Hodek for the ATARI-ACSI harddisk support
  44          and DMA handling.
  45        - Very limited information about moving packets in and out of the
  46          BIONET-adapter from the TCP package for TOS by BioData GmbH.
  47
  48        Theory of Operation
  49        -------------------
  50        Because the ATARI DMA port is usually shared between several
  51        devices (eg. harddisk, floppy) we cannot block the ACSI bus
  52        while waiting for interrupts. Therefore we use a polling mechanism
  53        to fetch packets from the adapter. For the same reason, we send
  54        packets without checking that the previous packet has been sent to
  55        the LAN. We rely on the higher levels of the networking code to detect
  56        missing packets and resend them.
  57
  58        Before we access the ATARI DMA controller, we check if another
  59        process is using the DMA. If not, we lock the DMA, perform one or
  60        more packet transfers and unlock the DMA before returning.
  61        We do not use 'stdma_lock' unconditionally because it is unclear
  62        if the networking code can be set to sleep, which will happen if
  63        another (possibly slow) device is using the DMA controller.
  64
  65        The polling is done via timer interrupts which periodically
  66        'simulate' an interrupt from the Ethernet adapter. The time (in jiffies)
  67        between polls varies depending on an estimate of the net activity.
  68        The allowed range is given by the variable 'bionet_min_poll_time'
  69        for the lower (fastest) limit and the constant 'MAX_POLL_TIME'
  70        for the higher (slowest) limit.
  71
  72        Whenever a packet arrives, we switch to fastest response by setting
  73        the polling time to its lowest limit. If the following poll fails,
  74        because no packets have arrived, we increase the time for the next
  75        poll. When the net activity is low, the polling time effectively
  76        stays at its maximum value, resulting in the lowest load for the
  77        machine.
  78 */
  79
  80#define MAX_POLL_TIME   10
  81
  82static char version[] =
  83        "bionet.c:v1.0 06-feb-96 (c) Hartmut Laue.\n";
  84
  85#include <linux/module.h>
  86
  87#include <linux/errno.h>
  88#include <linux/kernel.h>
  89#include <linux/jiffies.h>
  90#include <linux/types.h>
  91#include <linux/fcntl.h>
  92#include <linux/interrupt.h>
  93#include <linux/ioport.h>
  94#include <linux/in.h>
  95#include <linux/slab.h>
  96#include <linux/string.h>
  97#include <linux/delay.h>
  98#include <linux/timer.h>
  99#include <linux/init.h>
 100
 101#include <linux/netdevice.h>
 102#include <linux/etherdevice.h>
 103#include <linux/skbuff.h>
 104
 105#include <asm/setup.h>
 106#include <asm/pgtable.h>
 107#include <asm/system.h>
 108#include <asm/bitops.h>
 109#include <asm/io.h>
 110#include <asm/dma.h>
 111#include <asm/atarihw.h>
 112#include <asm/atariints.h>
 113#include <asm/atari_acsi.h>
 114#include <asm/atari_stdma.h>
 115
 116
 117/* use 0 for production, 1 for verification, >2 for debug
 118 */
 119#ifndef NET_DEBUG
 120#define NET_DEBUG 0
 121#endif
 122/*
 123 * Global variable 'bionet_debug'. Can be set at load time by 'insmod'
 124 */
 125unsigned int bionet_debug = NET_DEBUG;
 126MODULE_PARM(bionet_debug, "i");
 127MODULE_PARM_DESC(bionet_debug, "bionet debug level (0-2)");
 128MODULE_LICENSE("GPL");
 129
 130static unsigned int bionet_min_poll_time = 2;
 131
 132
 133/* Information that need to be kept for each board.
 134 */
 135struct net_local {
 136        struct net_device_stats stats;
 137        long open_time;                 /* for debugging */
 138        int  poll_time;                 /* polling time varies with net load */
 139};
 140
 141static struct nic_pkt_s {               /* packet format */
 142        unsigned char   status;
 143        unsigned char   dummy;
 144        unsigned char   l_lo, l_hi;
 145        unsigned char   buffer[3000];
 146} *nic_packet;
 147unsigned char *phys_nic_packet;
 148
 149/* Index to functions, as function prototypes.
 150 */
 151extern int bionet_probe(struct net_device *dev);
 152
 153static int bionet_open(struct net_device *dev);
 154static int bionet_send_packet(struct sk_buff *skb, struct net_device *dev);
 155static void bionet_poll_rx(struct net_device *);
 156static int bionet_close(struct net_device *dev);
 157static struct net_device_stats *net_get_stats(struct net_device *dev);
 158static void bionet_tick(unsigned long);
 159
 160static struct timer_list bionet_timer = TIMER_INITIALIZER(bionet_tick, 0, 0);
 161
 162#define STRAM_ADDR(a)   (((a) & 0xff000000) == 0)
 163
 164/* The following routines access the ethernet board connected to the
 165 * ACSI port via the st_dma chip.
 166 */
 167#define NODE_ADR 0x60
 168
 169#define C_READ 8
 170#define C_WRITE 0x0a
 171#define C_GETEA 0x0f
 172#define C_SETCR 0x0e
 173
 174static int
 175sendcmd(unsigned int a0, unsigned int mod, unsigned int cmd) {
 176        unsigned int c;
 177
 178        dma_wd.dma_mode_status = (mod | ((a0) ? 2 : 0) | 0x88);
 179        dma_wd.fdc_acces_seccount = cmd;
 180        dma_wd.dma_mode_status = (mod | 0x8a);
 181
 182        if( !acsi_wait_for_IRQ(HZ/2) )  /* wait for cmd ack */
 183                return -1;              /* timeout */
 184
 185        c = dma_wd.fdc_acces_seccount;
 186        return (c & 0xff);
 187}
 188
 189
 190static void
 191set_status(int cr) {
 192        sendcmd(0,0x100,NODE_ADR | C_SETCR);    /* CMD: SET CR */
 193        sendcmd(1,0x100,cr);
 194
 195        dma_wd.dma_mode_status = 0x80;
 196}
 197
 198static int
 199get_status(unsigned char *adr) {
 200        int i,c;
 201
 202        DISABLE_IRQ();
 203        c = sendcmd(0,0x00,NODE_ADR | C_GETEA);  /* CMD: GET ETH ADR*/
 204        if( c < 0 ) goto gsend;
 205
 206        /* now read status bytes */
 207
 208        for (i=0; i<6; i++) {
 209                dma_wd.fdc_acces_seccount = 0;  /* request next byte */
 210
 211                if( !acsi_wait_for_IRQ(HZ/2) ) {        /* wait for cmd ack */
 212                        c = -1;
 213                        goto gsend;             /* timeout */
 214                }
 215                c = dma_wd.fdc_acces_seccount;
 216                *adr++ = (unsigned char)c;
 217        }
 218        c = 1;
 219gsend:
 220        dma_wd.dma_mode_status = 0x80;
 221        return c;
 222}
 223
 224static irqreturn_t
 225bionet_intr(int irq, void *data, struct pt_regs *fp) {
 226        return IRQ_HANDLED;
 227}
 228
 229
 230static int
 231get_frame(unsigned long paddr, int odd) {
 232        int c;
 233        unsigned long flags;
 234
 235        DISABLE_IRQ();
 236        local_irq_save(flags);
 237
 238        dma_wd.dma_mode_status          = 0x9a;
 239        dma_wd.dma_mode_status          = 0x19a;
 240        dma_wd.dma_mode_status          = 0x9a;
 241        dma_wd.fdc_acces_seccount       = 0x04;         /* sector count (was 5) */
 242        dma_wd.dma_lo                   = (unsigned char)paddr;
 243        paddr >>= 8;
 244        dma_wd.dma_md                   = (unsigned char)paddr;
 245        paddr >>= 8;
 246        dma_wd.dma_hi                   = (unsigned char)paddr;
 247        local_irq_restore(flags);
 248
 249        c = sendcmd(0,0x00,NODE_ADR | C_READ);  /* CMD: READ */
 250        if( c < 128 ) goto rend;
 251
 252        /* now read block */
 253
 254        c = sendcmd(1,0x00,odd);        /* odd flag for address shift */
 255        dma_wd.dma_mode_status  = 0x0a;
 256
 257        if( !acsi_wait_for_IRQ(100) ) { /* wait for DMA to complete */
 258                c = -1;
 259                goto rend;
 260        }
 261        dma_wd.dma_mode_status  = 0x8a;
 262        dma_wd.dma_mode_status  = 0x18a;
 263        dma_wd.dma_mode_status  = 0x8a;
 264        c = dma_wd.fdc_acces_seccount;
 265
 266        dma_wd.dma_mode_status  = 0x88;
 267        c = dma_wd.fdc_acces_seccount;
 268        c = 1;
 269
 270rend:
 271        dma_wd.dma_mode_status  = 0x80;
 272        udelay(40);
 273        acsi_wait_for_noIRQ(20);
 274        return c;
 275}
 276
 277
 278static int
 279hardware_send_packet(unsigned long paddr, int cnt) {
 280        unsigned int c;
 281        unsigned long flags;
 282
 283        DISABLE_IRQ();
 284        local_irq_save(flags);
 285
 286        dma_wd.dma_mode_status  = 0x19a;
 287        dma_wd.dma_mode_status  = 0x9a;
 288        dma_wd.dma_mode_status  = 0x19a;
 289        dma_wd.dma_lo           = (unsigned char)paddr;
 290        paddr >>= 8;
 291        dma_wd.dma_md           = (unsigned char)paddr;
 292        paddr >>= 8;
 293        dma_wd.dma_hi           = (unsigned char)paddr;
 294
 295        dma_wd.fdc_acces_seccount       = 0x4;          /* sector count */
 296        local_irq_restore(flags);
 297
 298        c = sendcmd(0,0x100,NODE_ADR | C_WRITE);        /* CMD: WRITE */
 299        c = sendcmd(1,0x100,cnt&0xff);
 300        c = sendcmd(1,0x100,cnt>>8);
 301
 302        /* now write block */
 303
 304        dma_wd.dma_mode_status  = 0x10a;        /* DMA enable */
 305        if( !acsi_wait_for_IRQ(100) )           /* wait for DMA to complete */
 306                goto end;
 307
 308        dma_wd.dma_mode_status  = 0x19a;        /* DMA disable ! */
 309        c = dma_wd.fdc_acces_seccount;
 310
 311end:
 312        c = sendcmd(1,0x100,0);
 313        c = sendcmd(1,0x100,0);
 314
 315        dma_wd.dma_mode_status  = 0x180;
 316        udelay(40);
 317        acsi_wait_for_noIRQ(20);
 318        return( c & 0x02);
 319}
 320
 321
 322/* Check for a network adaptor of this type, and return '0' if one exists.
 323 */
 324int __init 
 325bionet_probe(struct net_device *dev){
 326        unsigned char station_addr[6];
 327        static unsigned version_printed;
 328        static int no_more_found;       /* avoid "Probing for..." printed 4 times */
 329        int i;
 330
 331        if (!MACH_IS_ATARI || no_more_found)
 332                return -ENODEV;
 333
 334        printk("Probing for BioNet 100 Adapter...\n");
 335
 336        stdma_lock(bionet_intr, NULL);
 337        i = get_status(station_addr);   /* Read the station address PROM.  */
 338        ENABLE_IRQ();
 339        stdma_release();
 340
 341        /* Check the first three octets of the S.A. for the manufactor's code.
 342         */
 343
 344        if( i < 0
 345        ||  station_addr[0] != 'B'
 346        ||  station_addr[1] != 'I'
 347        ||  station_addr[2] != 'O' ) {
 348                no_more_found = 1;
 349                printk( "No BioNet 100 found.\n" );
 350                return -ENODEV;
 351        }
 352
 353        SET_MODULE_OWNER(dev);
 354
 355        if (bionet_debug > 0 && version_printed++ == 0)
 356                printk(version);
 357
 358        printk("%s: %s found, eth-addr: %02x-%02x-%02x:%02x-%02x-%02x.\n",
 359                dev->name, "BioNet 100",
 360                station_addr[0], station_addr[1], station_addr[2],
 361                station_addr[3], station_addr[4], station_addr[5]);
 362
 363        /* Initialize the device structure. */
 364
 365        nic_packet = (struct nic_pkt_s *)acsi_buffer;
 366        phys_nic_packet = (unsigned char *)phys_acsi_buffer;
 367        if (bionet_debug > 0) {
 368                printk("nic_packet at 0x%p, phys at 0x%p\n",
 369                        nic_packet, phys_nic_packet );
 370        }
 371
 372        if (dev->priv == NULL)
 373                dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
 374        if (!dev->priv)
 375                return -ENOMEM;
 376        memset(dev->priv, 0, sizeof(struct net_local));
 377
 378        dev->open               = bionet_open;
 379        dev->stop               = bionet_close;
 380        dev->hard_start_xmit    = bionet_send_packet;
 381        dev->get_stats          = net_get_stats;
 382
 383        /* Fill in the fields of the device structure with ethernet-generic
 384         * values. This should be in a common file instead of per-driver.
 385         */
 386
 387        for (i = 0; i < ETH_ALEN; i++) {
 388#if 0
 389                dev->broadcast[i] = 0xff;
 390#endif
 391                dev->dev_addr[i]  = station_addr[i];
 392        }
 393        ether_setup(dev);
 394        return 0;
 395}
 396
 397/* Open/initialize the board.  This is called (in the current kernel)
 398   sometime after booting when the 'ifconfig' program is run.
 399
 400   This routine should set everything up anew at each open, even
 401   registers that "should" only need to be set once at boot, so that
 402   there is non-reboot way to recover if something goes wrong.
 403 */
 404static int
 405bionet_open(struct net_device *dev) {
 406        struct net_local *lp = (struct net_local *)dev->priv;
 407
 408        if (bionet_debug > 0)
 409                printk("bionet_open\n");
 410        stdma_lock(bionet_intr, NULL);
 411
 412        /* Reset the hardware here.
 413         */
 414        set_status(4);
 415        lp->open_time = 0;      /*jiffies*/
 416        lp->poll_time = MAX_POLL_TIME;
 417
 418        dev->tbusy = 0;
 419        dev->interrupt = 0;
 420        dev->start = 1;
 421
 422        stdma_release();
 423        bionet_timer.data = (long)dev;
 424        bionet_timer.expires = jiffies + lp->poll_time;
 425        add_timer(&bionet_timer);
 426        return 0;
 427}
 428
 429static int
 430bionet_send_packet(struct sk_buff *skb, struct net_device *dev) {
 431        struct net_local *lp = (struct net_local *)dev->priv;
 432        unsigned long flags;
 433
 434        /* Block a timer-based transmit from overlapping.  This could better be
 435         * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
 436         */
 437        local_irq_save(flags);
 438
 439        if (stdma_islocked()) {
 440                local_irq_restore(flags);
 441                lp->stats.tx_errors++;
 442        }
 443        else {
 444                int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 445                unsigned long buf = virt_to_phys(skb->data);
 446                int stat;
 447
 448                stdma_lock(bionet_intr, NULL);
 449                local_irq_restore(flags);
 450                if( !STRAM_ADDR(buf+length-1) ) {
 451                        memcpy(nic_packet->buffer, skb->data, length);
 452                        buf = (unsigned long)&((struct nic_pkt_s *)phys_nic_packet)->buffer;
 453                }
 454
 455                if (bionet_debug >1) {
 456                        u_char *data = nic_packet->buffer, *p;
 457                        int i;
 458                        
 459                        printk( "%s: TX pkt type 0x%4x from ", dev->name,
 460                                  ((u_short *)data)[6]);
 461
 462                        for( p = &data[6], i = 0; i < 6; i++ )
 463                                printk("%02x%s", *p++,i != 5 ? ":" : "" );
 464                        printk(" to ");
 465
 466                        for( p = data, i = 0; i < 6; i++ )
 467                                printk("%02x%s", *p++,i != 5 ? ":" : "" "\n" );
 468
 469                        printk( "%s: ", dev->name );
 470                        printk(" data %02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x"
 471                               " %02x%02x%02x%02x len %d\n",
 472                                  data[12], data[13], data[14], data[15], data[16], data[17], data[18], data[19],
 473                                  data[20], data[21], data[22], data[23], data[24], data[25], data[26], data[27],
 474                                  data[28], data[29], data[30], data[31], data[32], data[33],
 475                                  length );
 476                }
 477                dma_cache_maintenance(buf, length, 1);
 478
 479                stat = hardware_send_packet(buf, length);
 480                ENABLE_IRQ();
 481                stdma_release();
 482
 483                dev->trans_start = jiffies;
 484                dev->tbusy       = 0;
 485                lp->stats.tx_packets++;
 486                lp->stats.tx_bytes+=length;
 487        }
 488        dev_kfree_skb(skb);
 489
 490        return 0;
 491}
 492
 493/* We have a good packet(s), get it/them out of the buffers.
 494 */
 495static void
 496bionet_poll_rx(struct net_device *dev) {
 497        struct net_local *lp = (struct net_local *)dev->priv;
 498        int boguscount = 10;
 499        int pkt_len, status;
 500        unsigned long flags;
 501
 502        local_irq_save(flags);
 503        /* ++roman: Take care at locking the ST-DMA... This must be done with ints
 504         * off, since otherwise an int could slip in between the question and the
 505         * locking itself, and then we'd go to sleep... And locking itself is
 506         * necessary to keep the floppy_change timer from working with ST-DMA
 507         * registers. */
 508        if (stdma_islocked()) {
 509                local_irq_restore(flags);
 510                return;
 511        }
 512        stdma_lock(bionet_intr, NULL);
 513        DISABLE_IRQ();
 514        local_irq_restore(flags);
 515
 516        if( lp->poll_time < MAX_POLL_TIME ) lp->poll_time++;
 517
 518        while(boguscount--) {
 519                status = get_frame((unsigned long)phys_nic_packet, 0);
 520
 521                if( status == 0 ) break;
 522
 523                /* Good packet... */
 524
 525                dma_cache_maintenance((unsigned long)phys_nic_packet, 1520, 0);
 526
 527                pkt_len = (nic_packet->l_hi << 8) | nic_packet->l_lo;
 528
 529                lp->poll_time = bionet_min_poll_time;    /* fast poll */
 530                if( pkt_len >= 60 && pkt_len <= 1520 ) {
 531                                        /*      ^^^^ war 1514  KHL */
 532                        /* Malloc up new buffer.
 533                         */
 534                        struct sk_buff *skb = dev_alloc_skb( pkt_len + 2 );
 535                        if (skb == NULL) {
 536                                printk("%s: Memory squeeze, dropping packet.\n",
 537                                        dev->name);
 538                                lp->stats.rx_dropped++;
 539                                break;
 540                        }
 541
 542                        skb->dev = dev;
 543                        skb_reserve( skb, 2 );          /* 16 Byte align  */
 544                        skb_put( skb, pkt_len );        /* make room */
 545
 546                        /* 'skb->data' points to the start of sk_buff data area.
 547                         */
 548                        memcpy(skb->data, nic_packet->buffer, pkt_len);
 549                        skb->protocol = eth_type_trans( skb, dev ); 
 550                        netif_rx(skb);
 551                        dev->last_rx = jiffies;
 552                        lp->stats.rx_packets++;
 553                        lp->stats.rx_bytes+=pkt_len;
 554
 555        /* If any worth-while packets have been received, dev_rint()
 556           has done a mark_bh(INET_BH) for us and will work on them
 557           when we get to the bottom-half routine.
 558         */
 559
 560                        if (bionet_debug >1) {
 561                                u_char *data = nic_packet->buffer, *p;
 562                                int i;
 563                                
 564                                printk( "%s: RX pkt type 0x%4x from ", dev->name,
 565                                          ((u_short *)data)[6]);
 566                                         
 567                                
 568                                for( p = &data[6], i = 0; i < 6; i++ )
 569                                        printk("%02x%s", *p++,i != 5 ? ":" : "" );
 570                                printk(" to ");
 571                                for( p = data, i = 0; i < 6; i++ )
 572                                        printk("%02x%s", *p++,i != 5 ? ":" : "" "\n" );
 573 
 574                                printk( "%s: ", dev->name );
 575                                printk(" data %02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x"
 576                                       " %02x%02x%02x%02x len %d\n",
 577                                          data[12], data[13], data[14], data[15], data[16], data[17], data[18], data[19],
 578                                          data[20], data[21], data[22], data[23], data[24], data[25], data[26], data[27],
 579                                          data[28], data[29], data[30], data[31], data[32], data[33],
 580                                                  pkt_len );
 581                        }
 582                }
 583                else {
 584                        printk(" Packet has wrong length: %04d bytes\n", pkt_len);
 585                        lp->stats.rx_errors++;
 586                }
 587        }
 588        stdma_release();
 589        ENABLE_IRQ();
 590        return;
 591}
 592
 593/* bionet_tick: called by bionet_timer. Reads packets from the adapter,
 594 * passes them to the higher layers and restarts the timer.
 595 */
 596static void
 597bionet_tick(unsigned long data) {
 598        struct net_device        *dev = (struct net_device *)data;
 599        struct net_local *lp = (struct net_local *)dev->priv;
 600
 601        if( bionet_debug > 0 && (lp->open_time++ & 7) == 8 )
 602                printk("bionet_tick: %ld\n", lp->open_time);
 603
 604        if( !stdma_islocked() ) bionet_poll_rx(dev);
 605
 606        bionet_timer.expires = jiffies + lp->poll_time;
 607        add_timer(&bionet_timer);
 608}
 609
 610/* The inverse routine to bionet_open().
 611 */
 612static int
 613bionet_close(struct net_device *dev) {
 614        struct net_local *lp = (struct net_local *)dev->priv;
 615
 616        if (bionet_debug > 0)
 617                printk("bionet_close, open_time=%ld\n", lp->open_time);
 618        del_timer(&bionet_timer);
 619        stdma_lock(bionet_intr, NULL);
 620
 621        set_status(0);
 622        lp->open_time = 0;
 623
 624        dev->tbusy = 1;
 625        dev->start = 0;
 626
 627        stdma_release();
 628        return 0;
 629}
 630
 631/* Get the current statistics.
 632   This may be called with the card open or closed.
 633 */
 634static struct net_device_stats *net_get_stats(struct net_device *dev) 
 635{
 636        struct net_local *lp = (struct net_local *)dev->priv;
 637        return &lp->stats;
 638}
 639
 640
 641#ifdef MODULE
 642
 643static struct net_device bio_dev;
 644
 645int
 646init_module(void) {
 647        int err;
 648
 649        bio_dev.init = bionet_probe;
 650        if ((err = register_netdev(&bio_dev))) {
 651                if (err == -EEXIST)  {
 652                        printk("BIONET: devices already present. Module not loaded.\n");
 653                }
 654                return err;
 655        }
 656        return 0;
 657}
 658
 659void
 660cleanup_module(void) {
 661        unregister_netdev(&bio_dev);
 662}
 663
 664#endif /* MODULE */
 665
 666/* Local variables:
 667 *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include
 668        -b m68k-linuxaout -Wall -Wstrict-prototypes -O2
 669        -fomit-frame-pointer -pipe -DMODULE -I../../net/inet -c bionet.c"
 670 *  version-control: t
 671 *  kept-new-versions: 5
 672 *  tab-width: 8
 673 * End:
 674 */
 675
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.