root/drivers/net/skeleton.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. netcard_probe
  2. netcard_probe1
  3. net_open
  4. net_send_packet
  5. net_interrupt
  6. net_rx
  7. net_close
  8. net_get_stats
  9. set_multicast_list

   1 /* skeleton.c: A sample network driver core for linux. */
   2 /*
   3         Written 1993 by Donald Becker.
   4         Copyright 1993 United States Government as represented by the Director,
   5         National Security Agency.  This software may only be used and distributed
   6         according to the terms of the GNU Public License as modified by SRC,
   7         incorporated herein by reference.
   8 
   9         The author may be reached as becker@super.org or
  10         C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
  11 
  12         This file is an outline for writing a network device driver for the
  13         the Linux operating system.
  14 
  15         To write (or understand) a driver, have a look at the "loopback.c" file to
  16         get a feel of what is going on, and then use the code below as a skeleton
  17         for the new driver.
  18 
  19 */
  20 
  21 static char *version =
  22         "skeleton.c:v0.05 11/16/93 Donald Becker (becker@super.org)\n";
  23 
  24 /* Always include 'config.h' first in case the user wants to turn on
  25    or override something. */
  26 #include <linux/config.h>
  27 
  28 /*
  29   Sources:
  30         List your sources of programming information to document that
  31         the driver is your own creation, and give due credit to others
  32         that contributed to the work.  Remember that GNU project code
  33         cannot use proprietary or trade secret information.      Interface
  34         definitions are generally considered non-copyrightable to the
  35         extent that the same names and structures must be used to be
  36         compatible.
  37 
  38         Finally, keep in mind that the Linux kernel is has an API, not
  39         ABI.  Proprietary object-code-only distributions are not permitted
  40         under the GPL.
  41 */
  42 
  43 #include <linux/kernel.h>
  44 #include <linux/sched.h>
  45 #include <linux/types.h>
  46 #include <linux/fcntl.h>
  47 #include <linux/interrupt.h>
  48 #include <linux/ptrace.h>
  49 #include <linux/ioport.h>
  50 #include <linux/in.h>
  51 #include <linux/malloc.h>
  52 #include <linux/string.h>
  53 #include <asm/system.h>
  54 #include <asm/bitops.h>
  55 #include <asm/io.h>
  56 #include <asm/dma.h>
  57 #include <errno.h>
  58 
  59 #include <linux/netdevice.h>
  60 #include <linux/etherdevice.h>
  61 #include <linux/skbuff.h>
  62 
  63 #ifndef HAVE_AUTOIRQ
  64 /* From auto_irq.c, in ioport.h for later versions. */
  65 extern void autoirq_setup(int waittime);
  66 extern int autoirq_report(int waittime);
  67 /* The map from IRQ number (as passed to the interrupt handler) to
  68    'struct device'. */
  69 extern struct device *irq2dev_map[16];
  70 #endif
  71 
  72 #ifndef HAVE_PORTRESERVE
  73 #define check_region(ioaddr, size)              0
  74 #define snarf_region(ioaddr, size);             do ; while (0)
  75 #endif
  76 
  77 /* use 0 for production, 1 for verification, >2 for debug */
  78 #ifndef NET_DEBUG
  79 #define NET_DEBUG 2
  80 #endif
  81 static unsigned int net_debug = NET_DEBUG;
  82 
  83 /* Information that need to be kept for each board. */
  84 struct net_local {
  85         struct enet_statistics stats;
  86         long open_time;                         /* Useless example local info. */
  87 };
  88 
  89 /* The number of low I/O ports used by the ethercard. */
  90 #define ETHERCARD_TOTAL_SIZE    16
  91 
  92 /* The station (ethernet) address prefix, used for IDing the board. */
  93 #define SA_ADDR0 0x00
  94 #define SA_ADDR1 0x42
  95 #define SA_ADDR2 0x65
  96 
  97 /* Index to functions, as function prototypes. */
  98 
  99 extern int netcard_probe(struct device *dev);
 100 
 101 static int netcard_probe1(struct device *dev, short ioaddr);
 102 static int net_open(struct device *dev);
 103 static int      net_send_packet(struct sk_buff *skb, struct device *dev);
 104 static void net_interrupt(int reg_ptr);
 105 static void net_rx(struct device *dev);
 106 static int net_close(struct device *dev);
 107 static struct enet_statistics *net_get_stats(struct device *dev);
 108 static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
 109 
 110 /* Example routines you must write ;->. */
 111 #define tx_done(dev) 1
 112 extern void     hardware_send_packet(short ioaddr, char *buf, int length);
 113 extern void chipset_init(struct device *dev, int startp);
 114 
 115 
 116 /* Check for a network adaptor of this type, and return '0' iff one exists.
 117    If dev->base_addr == 0, probe all likely locations.
 118    If dev->base_addr == 1, always return failure.
 119    If dev->base_addr == 2, alloate space for the device and return success
 120    (detachable devices only).
 121    */
 122 int
 123 netcard_probe(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 124 {
 125         int *port, ports[] = {0x300, 0x280, 0};
 126         int base_addr = dev->base_addr;
 127 
 128         if (base_addr > 0x1ff)          /* Check a single specified location. */
 129                 return netcard_probe1(dev, base_addr);
 130         else if (base_addr > 0)         /* Don't probe at all. */
 131                 return ENXIO;
 132 
 133         for (port = &ports[0]; *port; port++) {
 134                 int ioaddr = *port;
 135                 if (check_region(ioaddr, ETHERCARD_TOTAL_SIZE))
 136                         continue;
 137                 if (inb(ioaddr) != 0x57)
 138                         continue;
 139                 dev->base_addr = ioaddr;
 140                 if (netcard_probe1(dev, ioaddr) == 0)
 141                         return 0;
 142         }
 143 
 144         dev->base_addr = base_addr;
 145         return ENODEV;
 146 }
 147 
 148 int netcard_probe1(struct device *dev, short ioaddr)
     /* [previous][next][first][last][top][bottom][index][help] */
 149 {
 150         unsigned char station_addr[6];
 151         int i;
 152 
 153         /* Read the station address PROM.  */
 154         for (i = 0; i < 6; i++) {
 155                 station_addr[i] = inb(ioaddr + i);
 156         }
 157         /* Check the first three octets of the S.A. for the manufactor's code. */ 
 158         if (station_addr[0] != SA_ADDR0
 159                 ||       station_addr[1] != SA_ADDR1 || station_addr[2] != SA_ADDR2) {
 160                 return ENODEV;
 161         }
 162 
 163         printk("%s: %s found at %#3x, IRQ %d.\n", dev->name,
 164                    "network card", dev->base_addr, dev->irq);
 165 
 166 #ifdef jumpered_interrupts
 167         /* If this board has jumpered interrupts, snarf the interrupt vector
 168            now.  There is no point in waiting since no other device can use
 169            the interrupt, and this marks the 'irqaction' as busy. */
 170 
 171         if (dev->irq == -1)
 172                 ;                       /* Do nothing: a user-level program will set it. */
 173         else if (dev->irq < 2) {        /* "Auto-IRQ" */
 174                 autoirq_setup(0);
 175                 /* Trigger an interrupt here. */
 176 
 177                 dev->irq = autoirq_report(0);
 178                 if (net_debug >= 2)
 179                         printk(" autoirq is %d", dev->irq);
 180   } else if (dev->irq == 2)
 181           /* Fixup for users that don't know that IRQ 2 is really IRQ 9,
 182          or don't know which one to set. */
 183           dev->irq = 9;
 184 
 185         {        int irqval = request_irq(dev->irq, &net_interrupt);
 186                  if (irqval) {
 187                          printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name,
 188                                          dev->irq, irqval);
 189                          return EAGAIN;
 190                  }
 191          }
 192 #endif  /* jumpered interrupt */
 193 
 194         /* Grab the region so we can find another board if autoIRQ fails. */
 195         snarf_region(ioaddr, ETHERCARD_TOTAL_SIZE);
 196 
 197         if (net_debug)
 198                 printk(version);
 199 
 200         /* Initialize the device structure. */
 201         dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
 202         memset(dev->priv, 0, sizeof(struct net_local));
 203 
 204         dev->open               = net_open;
 205         dev->stop               = net_close;
 206         dev->hard_start_xmit = net_send_packet;
 207         dev->get_stats  = net_get_stats;
 208         dev->set_multicast_list = &set_multicast_list;
 209 
 210         /* Fill in the fields of the device structure with ethernet-generic values. */
 211         
 212         ether_setup(dev);
 213 
 214         return 0;
 215 }
 216 
 217 
 218 /* Open/initialize the board.  This is called (in the current kernel)
 219    sometime after booting when the 'ifconfig' program is run.
 220 
 221    This routine should set everything up anew at each open, even
 222    registers that "should" only need to be set once at boot, so that
 223    there is non-reboot way to recover if something goes wrong.
 224    */
 225 static int
 226 net_open(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 227 {
 228         struct net_local *lp = (struct net_local *)dev->priv;
 229         int ioaddr = dev->base_addr;
 230 
 231         /* This is used if the interrupt line can turned off (shared).
 232            See 3c503.c for an example of selecting the IRQ at config-time. */
 233         if (request_irq(dev->irq, &net_interrupt)) {
 234                 return -EAGAIN;
 235         }
 236 
 237 
 238         /* Always snarf a DMA channel after the IRQ. */
 239         if (request_dma(dev->dma)) {
 240                 free_irq(dev->irq);
 241                 return -EAGAIN;
 242         }
 243         irq2dev_map[dev->irq] = dev;
 244 
 245         /* Reset the hardware here. */
 246         /*chipset_init(dev, 1);*/
 247         outb(0x00, ioaddr);
 248         lp->open_time = jiffies;
 249 
 250         dev->tbusy = 0;
 251         dev->interrupt = 0;
 252         dev->start = 1;
 253         return 0;
 254 }
 255 
 256 static int
 257 net_send_packet(struct sk_buff *skb, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 258 {
 259         struct net_local *lp = (struct net_local *)dev->priv;
 260         int ioaddr = dev->base_addr;
 261 
 262         if (dev->tbusy) {
 263                 /* If we get here, some higher level has decided we are broken.
 264                    There should really be a "kick me" function call instead. */
 265                 int tickssofar = jiffies - dev->trans_start;
 266                 if (tickssofar < 5)
 267                         return 1;
 268                 printk("%s: transmit timed out, %s?\n", dev->name,
 269                            tx_done(dev) ? "IRQ conflict" : "network cable problem");
 270                 /* Try to restart the adaptor. */
 271                 chipset_init(dev, 1);
 272                 dev->tbusy=0;
 273                 dev->trans_start = jiffies;
 274         }
 275 
 276         /* If some higher layer thinks we've missed an tx-done interrupt
 277            we are passed NULL. Caution: dev_tint() handles the cli()/sti()
 278            itself. */
 279         if (skb == NULL) {
 280                 dev_tint(dev);
 281                 return 0;
 282         }
 283 
 284         /* Block a timer-based transmit from overlapping.  This could better be
 285            done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
 286         if (set_bit(0, (void*)&dev->tbusy) != 0)
 287                 printk("%s: Transmitter access conflict.\n", dev->name);
 288         else {
 289                 short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 290                 unsigned char *buf = skb->data;
 291 
 292                 hardware_send_packet(ioaddr, buf, length);
 293                 dev->trans_start = jiffies;
 294         }
 295         dev_kfree_skb (skb, FREE_WRITE);
 296 
 297         /* You might need to clean up and record Tx statistics here. */
 298         if (inw(ioaddr) == /*RU*/81)
 299                 lp->stats.tx_aborted_errors++;
 300 
 301         return 0;
 302 }
 303 
 304 /* The typical workload of the driver:
 305    Handle the network interface interrupts. */
 306 static void
 307 net_interrupt(int reg_ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 308 {
 309         int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
 310         struct device *dev = (struct device *)(irq2dev_map[irq]);
 311         struct net_local *lp;
 312         int ioaddr, status, boguscount = 0;
 313 
 314         if (dev == NULL) {
 315                 printk ("net_interrupt(): irq %d for unknown device.\n", irq);
 316                 return;
 317         }
 318         dev->interrupt = 1;
 319 
 320         ioaddr = dev->base_addr;
 321         lp = (struct net_local *)dev->priv;
 322         status = inw(ioaddr + 0);
 323 
 324         do {
 325                 if (status /*& RX_INTR*/) {
 326                         /* Got a packet(s). */
 327                         net_rx(dev);
 328                 }
 329                 if (status /*& TX_INTR*/) {
 330                         lp->stats.tx_packets++;
 331                         dev->tbusy = 0;
 332                         mark_bh(NET_BH);        /* Inform upper layers. */
 333                 }
 334                 if (status /*& COUNTERS_INTR*/) {
 335                         /* Increment the appropriate 'localstats' field. */
 336                         lp->stats.tx_window_errors++;
 337                 }
 338         } while (++boguscount < 20) ;
 339 
 340         return;
 341 }
 342 
 343 /* We have a good packet(s), get it/them out of the buffers. */
 344 static void
 345 net_rx(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 346 {
 347         struct net_local *lp = (struct net_local *)dev->priv;
 348         int ioaddr = dev->base_addr;
 349         int boguscount = 10;
 350 
 351         do {
 352                 int status = inw(ioaddr);
 353                 int pkt_len = inw(ioaddr);
 354           
 355                 if (pkt_len == 0)               /* Read all the frames? */
 356                         break;                  /* Done for now */
 357 
 358                 if (status & 0x40) {    /* There was an error. */
 359                         lp->stats.rx_errors++;
 360                         if (status & 0x20) lp->stats.rx_frame_errors++;
 361                         if (status & 0x10) lp->stats.rx_over_errors++;
 362                         if (status & 0x08) lp->stats.rx_crc_errors++;
 363                         if (status & 0x04) lp->stats.rx_fifo_errors++;
 364                 } else {
 365                         /* Malloc up new buffer. */
 366                         struct sk_buff *skb;
 367 
 368                         skb = alloc_skb(pkt_len, GFP_ATOMIC);
 369                         if (skb == NULL) {
 370                                 printk("%s: Memory squeeze, dropping packet.\n", dev->name);
 371                                 lp->stats.rx_dropped++;
 372                                 break;
 373                         }
 374                         skb->len = pkt_len;
 375                         skb->dev = dev;
 376 
 377                         /* 'skb->data' points to the start of sk_buff data area. */
 378                         memcpy(skb->data, (void*)dev->rmem_start,
 379                                    pkt_len);
 380                         /* or */
 381                         insw(ioaddr, skb->data, (pkt_len + 1) >> 1);
 382 
 383                         netif_rx(skb);
 384                         lp->stats.rx_packets++;
 385                 }
 386         } while (--boguscount);
 387 
 388         /* If any worth-while packets have been received, dev_rint()
 389            has done a mark_bh(NET_BH) for us and will work on them
 390            when we get to the bottom-half routine. */
 391         return;
 392 }
 393 
 394 /* The inverse routine to net_open(). */
 395 static int
 396 net_close(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 397 {
 398         struct net_local *lp = (struct net_local *)dev->priv;
 399         int ioaddr = dev->base_addr;
 400 
 401         lp->open_time = 0;
 402 
 403         dev->tbusy = 1;
 404         dev->start = 0;
 405 
 406         /* Flush the Tx and disable Rx here. */
 407 
 408         disable_dma(dev->dma);
 409 
 410         /* If not IRQ or DMA jumpered, free up the line. */
 411         outw(0x00, ioaddr+0);           /* Release the physical interrupt line. */
 412 
 413         free_irq(dev->irq);
 414         free_dma(dev->dma);
 415 
 416         irq2dev_map[dev->irq] = 0;
 417 
 418         /* Update the statistics here. */
 419 
 420         return 0;
 421 
 422 }
 423 
 424 /* Get the current statistics.  This may be called with the card open or
 425    closed. */
 426 static struct enet_statistics *
 427 net_get_stats(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 428 {
 429         struct net_local *lp = (struct net_local *)dev->priv;
 430         short ioaddr = dev->base_addr;
 431 
 432         cli();
 433         /* Update the statistics from the device registers. */
 434         lp->stats.rx_missed_errors = inw(ioaddr+1);
 435         sti();
 436 
 437         return &lp->stats;
 438 }
 439 
 440 /* Set or clear the multicast filter for this adaptor.
 441    num_addrs == -1      Promiscuous mode, receive all packets
 442    num_addrs == 0       Normal mode, clear multicast list
 443    num_addrs > 0        Multicast mode, receive normal and MC packets, and do
 444                         best-effort filtering.
 445  */
 446 static void
 447 set_multicast_list(struct device *dev, int num_addrs, void *addrs)
     /* [previous][next][first][last][top][bottom][index][help] */
 448 {
 449         short ioaddr = dev->base_addr;
 450         if (num_addrs) {
 451                 outw(69, ioaddr);               /* Enable promiscuous mode */
 452         } else
 453                 outw(99, ioaddr);               /* Disable promiscuous mode, use normal mode */
 454 }
 455 
 456 /*
 457  * Local variables:
 458  *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c skeleton.c"
 459  *  version-control: t
 460  *  kept-new-versions: 5
 461  *  tab-width: 4
 462  * End:
 463  */

/* [previous][next][first][last][top][bottom][index][help] */