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
 117extern struct net_device *init_etherdev(struct net_device *dev, int sizeof_private);
 118
 119/* use 0 for production, 1 for verification, >2 for debug
 120 */
 121#ifndef NET_DEBUG
 122#define NET_DEBUG 0
 123#endif
 124/*
 125 * Global variable 'bionet_debug'. Can be set at load time by 'insmod'
 126 */
 127unsigned int bionet_debug = NET_DEBUG;
 128MODULE_PARM(bionet_debug, "i");
 129MODULE_PARM_DESC(bionet_debug, "bionet debug level (0-2)");
 130MODULE_LICENSE("GPL");
 131
 132static unsigned int bionet_min_poll_time = 2;
 133
 134
 135/* Information that need to be kept for each board.
 136 */
 137struct net_local {
 138        struct net_device_stats stats;
 139        long open_time;                 /* for debugging */
 140        int  poll_time;                 /* polling time varies with net load */
 141};
 142
 143static struct nic_pkt_s {               /* packet format */
 144        unsigned char   status;
 145        unsigned char   dummy;
 146        unsigned char   l_lo, l_hi;
 147        unsigned char   buffer[3000];
 148} *nic_packet;
 149unsigned char *phys_nic_packet;
 150
 151/* Index to functions, as function prototypes.
 152 */
 153extern int bionet_probe(struct net_device *dev);
 154
 155static int bionet_open(struct net_device *dev);
 156static int bionet_send_packet(struct sk_buff *skb, struct net_device *dev);
 157static void bionet_poll_rx(struct net_device *);
 158static int bionet_close(struct net_device *dev);
 159static struct net_device_stats *net_get_stats(struct net_device *dev);
 160static void bionet_tick(unsigned long);
 161
 162static struct timer_list bionet_timer = { function: bionet_tick };
 163
 164#define STRAM_ADDR(a)   (((a) & 0xff000000) == 0)
 165
 166/* The following routines access the ethernet board connected to the
 167 * ACSI port via the st_dma chip.
 168 */
 169#define NODE_ADR 0x60
 170
 171#define C_READ 8
 172#define C_WRITE 0x0a
 173#define C_GETEA 0x0f
 174#define C_SETCR 0x0e
 175
 176static int
 177sendcmd(unsigned int a0, unsigned int mod, unsigned int cmd) {
 178        unsigned int c;
 179
 180        dma_wd.dma_mode_status = (mod | ((a0) ? 2 : 0) | 0x88);
 181        dma_wd.fdc_acces_seccount = cmd;
 182        dma_wd.dma_mode_status = (mod | 0x8a);
 183
 184        if( !acsi_wait_for_IRQ(HZ/2) )  /* wait for cmd ack */
 185                return -1;              /* timeout */
 186
 187        c = dma_wd.fdc_acces_seccount;
 188        return (c & 0xff);
 189}
 190
 191
 192static void
 193set_status(int cr) {
 194        sendcmd(0,0x100,NODE_ADR | C_SETCR);    /* CMD: SET CR */
 195        sendcmd(1,0x100,cr);
 196
 197        dma_wd.dma_mode_status = 0x80;
 198}
 199
 200static int
 201get_status(unsigned char *adr) {
 202        int i,c;
 203
 204        DISABLE_IRQ();
 205        c = sendcmd(0,0x00,NODE_ADR | C_GETEA);  /* CMD: GET ETH ADR*/
 206        if( c < 0 ) goto gsend;
 207
 208        /* now read status bytes */
 209
 210        for (i=0; i<6; i++) {
 211                dma_wd.fdc_acces_seccount = 0;  /* request next byte */
 212
 213                if( !acsi_wait_for_IRQ(HZ/2) ) {        /* wait for cmd ack */
 214                        c = -1;
 215                        goto gsend;             /* timeout */
 216                }
 217                c = dma_wd.fdc_acces_seccount;
 218                *adr++ = (unsigned char)c;
 219        }
 220        c = 1;
 221gsend:
 222        dma_wd.dma_mode_status = 0x80;
 223        return c;
 224}
 225
 226static void
 227bionet_intr(int irq, void *data, struct pt_regs *fp) {
 228        return;
 229}
 230
 231
 232static int
 233get_frame(unsigned long paddr, int odd) {
 234        int c;
 235        unsigned long flags;
 236
 237        DISABLE_IRQ();
 238        save_flags(flags);
 239        cli();
 240
 241        dma_wd.dma_mode_status          = 0x9a;
 242        dma_wd.dma_mode_status          = 0x19a;
 243        dma_wd.dma_mode_status          = 0x9a;
 244        dma_wd.fdc_acces_seccount       = 0x04;         /* sector count (was 5) */
 245        dma_wd.dma_lo                   = (unsigned char)paddr;
 246        paddr >>= 8;
 247        dma_wd.dma_md                   = (unsigned char)paddr;
 248        paddr >>= 8;
 249        dma_wd.dma_hi                   = (unsigned char)paddr;
 250        restore_flags(flags);
 251
 252        c = sendcmd(0,0x00,NODE_ADR | C_READ);  /* CMD: READ */
 253        if( c < 128 ) goto rend;
 254
 255        /* now read block */
 256
 257        c = sendcmd(1,0x00,odd);        /* odd flag for address shift */
 258        dma_wd.dma_mode_status  = 0x0a;
 259
 260        if( !acsi_wait_for_IRQ(100) ) { /* wait for DMA to complete */
 261                c = -1;
 262                goto rend;
 263        }
 264        dma_wd.dma_mode_status  = 0x8a;
 265        dma_wd.dma_mode_status  = 0x18a;
 266        dma_wd.dma_mode_status  = 0x8a;
 267        c = dma_wd.fdc_acces_seccount;
 268
 269        dma_wd.dma_mode_status  = 0x88;
 270        c = dma_wd.fdc_acces_seccount;
 271        c = 1;
 272
 273rend:
 274        dma_wd.dma_mode_status  = 0x80;
 275        udelay(40);
 276        acsi_wait_for_noIRQ(20);
 277        return c;
 278}
 279
 280
 281static int
 282hardware_send_packet(unsigned long paddr, int cnt) {
 283        unsigned int c;
 284        unsigned long flags;
 285
 286        DISABLE_IRQ();
 287        save_flags(flags);
 288        cli();
 289
 290        dma_wd.dma_mode_status  = 0x19a;
 291        dma_wd.dma_mode_status  = 0x9a;
 292        dma_wd.dma_mode_status  = 0x19a;
 293        dma_wd.dma_lo           = (unsigned char)paddr;
 294        paddr >>= 8;
 295        dma_wd.dma_md           = (unsigned char)paddr;
 296        paddr >>= 8;
 297        dma_wd.dma_hi           = (unsigned char)paddr;
 298
 299        dma_wd.fdc_acces_seccount       = 0x4;          /* sector count */
 300        restore_flags(flags);
 301
 302        c = sendcmd(0,0x100,NODE_ADR | C_WRITE);        /* CMD: WRITE */
 303        c = sendcmd(1,0x100,cnt&0xff);
 304        c = sendcmd(1,0x100,cnt>>8);
 305
 306        /* now write block */
 307
 308        dma_wd.dma_mode_status  = 0x10a;        /* DMA enable */
 309        if( !acsi_wait_for_IRQ(100) )           /* wait for DMA to complete */
 310                goto end;
 311
 312        dma_wd.dma_mode_status  = 0x19a;        /* DMA disable ! */
 313        c = dma_wd.fdc_acces_seccount;
 314
 315end:
 316        c = sendcmd(1,0x100,0);
 317        c = sendcmd(1,0x100,0);
 318
 319        dma_wd.dma_mode_status  = 0x180;
 320        udelay(40);
 321        acsi_wait_for_noIRQ(20);
 322        return( c & 0x02);
 323}
 324
 325
 326/* Check for a network adaptor of this type, and return '0' if one exists.
 327 */
 328int __init 
 329bionet_probe(struct net_device *dev){
 330        unsigned char station_addr[6];
 331        static unsigned version_printed;
 332        static int no_more_found;       /* avoid "Probing for..." printed 4 times */
 333        int i;
 334
 335        if (!MACH_IS_ATARI || no_more_found)
 336                return -ENODEV;
 337
 338        printk("Probing for BioNet 100 Adapter...\n");
 339
 340        stdma_lock(bionet_intr, NULL);
 341        i = get_status(station_addr);   /* Read the station address PROM.  */
 342        ENABLE_IRQ();
 343        stdma_release();
 344
 345        /* Check the first three octets of the S.A. for the manufactor's code.
 346         */
 347
 348        if( i < 0
 349        ||  station_addr[0] != 'B'
 350        ||  station_addr[1] != 'I'
 351        ||  station_addr[2] != 'O' ) {
 352                no_more_found = 1;
 353                printk( "No BioNet 100 found.\n" );
 354                return -ENODEV;
 355        }
 356
 357        SET_MODULE_OWNER(dev);
 358
 359        if (bionet_debug > 0 && version_printed++ == 0)
 360                printk(version);
 361
 362        printk("%s: %s found, eth-addr: %02x-%02x-%02x:%02x-%02x-%02x.\n",
 363                dev->name, "BioNet 100",
 364                station_addr[0], station_addr[1], station_addr[2],
 365                station_addr[3], station_addr[4], station_addr[5]);
 366
 367        /* Initialize the device structure. */
 368
 369        nic_packet = (struct nic_pkt_s *)acsi_buffer;
 370        phys_nic_packet = (unsigned char *)phys_acsi_buffer;
 371        if (bionet_debug > 0) {
 372                printk("nic_packet at 0x%p, phys at 0x%p\n",
 373                        nic_packet, phys_nic_packet );
 374        }
 375
 376        if (dev->priv == NULL)
 377                dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
 378        if (!dev->priv)
 379                return -ENOMEM;
 380        memset(dev->priv, 0, sizeof(struct net_local));
 381
 382        dev->open               = bionet_open;
 383        dev->stop               = bionet_close;
 384        dev->hard_start_xmit    = bionet_send_packet;
 385        dev->get_stats          = net_get_stats;
 386
 387        /* Fill in the fields of the device structure with ethernet-generic
 388         * values. This should be in a common file instead of per-driver.
 389         */
 390
 391        for (i = 0; i < ETH_ALEN; i++) {
 392#if 0
 393                dev->broadcast[i] = 0xff;
 394#endif
 395                dev->dev_addr[i]  = station_addr[i];
 396        }
 397        ether_setup(dev);
 398        return 0;
 399}
 400
 401/* Open/initialize the board.  This is called (in the current kernel)
 402   sometime after booting when the 'ifconfig' program is run.
 403
 404   This routine should set everything up anew at each open, even
 405   registers that "should" only need to be set once at boot, so that
 406   there is non-reboot way to recover if something goes wrong.
 407 */
 408static int
 409bionet_open(struct net_device *dev) {
 410        struct net_local *lp = (struct net_local *)dev->priv;
 411
 412        if (bionet_debug > 0)
 413                printk("bionet_open\n");
 414        stdma_lock(bionet_intr, NULL);
 415
 416        /* Reset the hardware here.
 417         */
 418        set_status(4);
 419        lp->open_time = 0;      /*jiffies*/
 420        lp->poll_time = MAX_POLL_TIME;
 421
 422        dev->tbusy = 0;
 423        dev->interrupt = 0;
 424        dev->start = 1;
 425
 426        stdma_release();
 427        bionet_timer.data = (long)dev;
 428        bionet_timer.expires = jiffies + lp->poll_time;
 429        add_timer(&bionet_timer);
 430        return 0;
 431}
 432
 433static int
 434bionet_send_packet(struct sk_buff *skb, struct net_device *dev) {
 435        struct net_local *lp = (struct net_local *)dev->priv;
 436        unsigned long flags;
 437
 438        /* Block a timer-based transmit from overlapping.  This could better be
 439         * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
 440         */
 441        save_flags(flags);
 442        cli();
 443
 444        if (stdma_islocked()) {
 445                restore_flags(flags);
 446                lp->stats.tx_errors++;
 447        }
 448        else {
 449                int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 450                unsigned long buf = virt_to_phys(skb->data);
 451                int stat;
 452
 453                stdma_lock(bionet_intr, NULL);
 454                restore_flags(flags);
 455                if( !STRAM_ADDR(buf+length-1) ) {
 456                        memcpy(nic_packet->buffer, skb->data, length);
 457                        buf = (unsigned long)&((struct nic_pkt_s *)phys_nic_packet)->buffer;
 458                }
 459
 460                if (bionet_debug >1) {
 461                        u_char *data = nic_packet->buffer, *p;
 462                        int i;
 463                        
 464                        printk( "%s: TX pkt type 0x%4x from ", dev->name,
 465                                  ((u_short *)data)[6]);
 466
 467                        for( p = &data[6], i = 0; i < 6; i++ )
 468                                printk("%02x%s", *p++,i != 5 ? ":" : "" );
 469                        printk(" to ");
 470
 471                        for( p = data, i = 0; i < 6; i++ )
 472                                printk("%02x%s", *p++,i != 5 ? ":" : "" "\n" );
 473
 474                        printk( "%s: ", dev->name );
 475                        printk(" data %02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x"
 476                               " %02x%02x%02x%02x len %d\n",
 477                                  data[12], data[13], data[14], data[15], data[16], data[17], data[18], data[19],
 478                                  data[20], data[21], data[22], data[23], data[24], data[25], data[26], data[27],
 479                                  data[28], data[29], data[30], data[31], data[32], data[33],
 480                                  length );
 481                }
 482                dma_cache_maintenance(buf, length, 1);
 483
 484                stat = hardware_send_packet(buf, length);
 485                ENABLE_IRQ();
 486                stdma_release();
 487
 488                dev->trans_start = jiffies;
 489                dev->tbusy       = 0;
 490                lp->stats.tx_packets++;
 491                lp->stats.tx_bytes+=length;
 492        }
 493        dev_kfree_skb(skb);
 494
 495        return 0;
 496}
 497
 498/* We have a good packet(s), get it/them out of the buffers.
 499 */
 500static void
 501bionet_poll_rx(struct net_device *dev) {
 502        struct net_local *lp = (struct net_local *)dev->priv;
 503        int boguscount = 10;
 504        int pkt_len, status;
 505        unsigned long flags;
 506
 507        save_flags(flags);
 508        cli();
 509        /* ++roman: Take care at locking the ST-DMA... This must be done with ints
 510         * off, since otherwise an int could slip in between the question and the
 511         * locking itself, and then we'd go to sleep... And locking itself is
 512         * necessary to keep the floppy_change timer from working with ST-DMA
 513         * registers. */
 514        if (stdma_islocked()) {
 515                restore_flags(flags);
 516                return;
 517        }
 518        stdma_lock(bionet_intr, NULL);
 519        DISABLE_IRQ();
 520        restore_flags(flags);
 521
 522        if( lp->poll_time < MAX_POLL_TIME ) lp->poll_time++;
 523
 524        while(boguscount--) {
 525                status = get_frame((unsigned long)phys_nic_packet, 0);
 526
 527                if( status == 0 ) break;
 528
 529                /* Good packet... */
 530
 531                dma_cache_maintenance((unsigned long)phys_nic_packet, 1520, 0);
 532
 533                pkt_len = (nic_packet->l_hi << 8) | nic_packet->l_lo;
 534
 535                lp->poll_time = bionet_min_poll_time;    /* fast poll */
 536                if( pkt_len >= 60 && pkt_len <= 1520 ) {
 537                                        /*      ^^^^ war 1514  KHL */
 538                        /* Malloc up new buffer.
 539                         */
 540                        struct sk_buff *skb = dev_alloc_skb( pkt_len + 2 );
 541                        if (skb == NULL) {
 542                                printk("%s: Memory squeeze, dropping packet.\n",
 543                                        dev->name);
 544                                lp->stats.rx_dropped++;
 545                                break;
 546                        }
 547
 548                        skb->dev = dev;
 549                        skb_reserve( skb, 2 );          /* 16 Byte align  */
 550                        skb_put( skb, pkt_len );        /* make room */
 551
 552                        /* 'skb->data' points to the start of sk_buff data area.
 553                         */
 554                        memcpy(skb->data, nic_packet->buffer, pkt_len);
 555                        skb->protocol = eth_type_trans( skb, dev ); 
 556                        netif_rx(skb);
 557                        dev->last_rx = jiffies;
 558                        lp->stats.rx_packets++;
 559                        lp->stats.rx_bytes+=pkt_len;
 560
 561        /* If any worth-while packets have been received, dev_rint()
 562           has done a mark_bh(INET_BH) for us and will work on them
 563           when we get to the bottom-half routine.
 564         */
 565
 566                        if (bionet_debug >1) {
 567                                u_char *data = nic_packet->buffer, *p;
 568                                int i;
 569                                
 570                                printk( "%s: RX pkt type 0x%4x from ", dev->name,
 571                                          ((u_short *)data)[6]);
 572                                         
 573                                
 574                                for( p = &data[6], i = 0; i < 6; i++ )
 575                                        printk("%02x%s", *p++,i != 5 ? ":" : "" );
 576                                printk(" to ");
 577                                for( p = data, i = 0; i < 6; i++ )
 578                                        printk("%02x%s", *p++,i != 5 ? ":" : "" "\n" );
 579 
 580                                printk( "%s: ", dev->name );
 581                                printk(" data %02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x"
 582                                       " %02x%02x%02x%02x len %d\n",
 583                                          data[12], data[13], data[14], data[15], data[16], data[17], data[18], data[19],
 584                                          data[20], data[21], data[22], data[23], data[24], data[25], data[26], data[27],
 585                                          data[28], data[29], data[30], data[31], data[32], data[33],
 586                                                  pkt_len );
 587                        }
 588                }
 589                else {
 590                        printk(" Packet has wrong length: %04d bytes\n", pkt_len);
 591                        lp->stats.rx_errors++;
 592                }
 593        }
 594        stdma_release();
 595        ENABLE_IRQ();
 596        return;
 597}
 598
 599/* bionet_tick: called by bionet_timer. Reads packets from the adapter,
 600 * passes them to the higher layers and restarts the timer.
 601 */
 602static void
 603bionet_tick(unsigned long data) {
 604        struct net_device        *dev = (struct net_device *)data;
 605        struct net_local *lp = (struct net_local *)dev->priv;
 606
 607        if( bionet_debug > 0 && (lp->open_time++ & 7) == 8 )
 608                printk("bionet_tick: %ld\n", lp->open_time);
 609
 610        if( !stdma_islocked() ) bionet_poll_rx(dev);
 611
 612        bionet_timer.expires = jiffies + lp->poll_time;
 613        add_timer(&bionet_timer);
 614}
 615
 616/* The inverse routine to bionet_open().
 617 */
 618static int
 619bionet_close(struct net_device *dev) {
 620        struct net_local *lp = (struct net_local *)dev->priv;
 621
 622        if (bionet_debug > 0)
 623                printk("bionet_close, open_time=%ld\n", lp->open_time);
 624        del_timer(&bionet_timer);
 625        stdma_lock(bionet_intr, NULL);
 626
 627        set_status(0);
 628        lp->open_time = 0;
 629
 630        dev->tbusy = 1;
 631        dev->start = 0;
 632
 633        stdma_release();
 634        return 0;
 635}
 636
 637/* Get the current statistics.
 638   This may be called with the card open or closed.
 639 */
 640static struct net_device_stats *net_get_stats(struct net_device *dev) 
 641{
 642        struct net_local *lp = (struct net_local *)dev->priv;
 643        return &lp->stats;
 644}
 645
 646
 647#ifdef MODULE
 648
 649static struct net_device bio_dev;
 650
 651int
 652init_module(void) {
 653        int err;
 654
 655        bio_dev.init = bionet_probe;
 656        if ((err = register_netdev(&bio_dev))) {
 657                if (err == -EEXIST)  {
 658                        printk("BIONET: devices already present. Module not loaded.\n");
 659                }
 660                return err;
 661        }
 662        return 0;
 663}
 664
 665void
 666cleanup_module(void) {
 667        unregister_netdev(&bio_dev);
 668}
 669
 670#endif /* MODULE */
 671
 672/* Local variables:
 673 *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include
 674        -b m68k-linuxaout -Wall -Wstrict-prototypes -O2
 675        -fomit-frame-pointer -pipe -DMODULE -I../../net/inet -c bionet.c"
 676 *  version-control: t
 677 *  kept-new-versions: 5
 678 *  tab-width: 8
 679 * End:
 680 */
 681
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.