root/drivers/net/net_init.c

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

DEFINITIONS

This source file includes following definitions.
  1. init_etherdev
  2. eth_mac_addr
  3. ether_setup
  4. tr_setup
  5. ether_config
  6. register_netdev
  7. unregister_netdev

   1 /* netdrv_init.c: Initialization for network devices. */
   2 /*
   3         Written 1993,1994,1995 by Donald Becker.
   4 
   5         The author may be reached as becker@cesdis.gsfc.nasa.gov or
   6         C/O Center of Excellence in Space Data and Information Sciences
   7                 Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
   8 
   9         This file contains the initialization for the "pl14+" style ethernet
  10         drivers.  It should eventually replace most of drivers/net/Space.c.
  11         It's primary advantage is that it's able to allocate low-memory buffers.
  12         A secondary advantage is that the dangerous NE*000 netcards can reserve
  13         their I/O port region before the SCSI probes start.
  14 
  15         Modifications/additions by Bjorn Ekwall <bj0rn@blox.se>:
  16                 ethdev_index[MAX_ETH_CARDS]
  17                 register_netdev() / unregister_netdev()
  18                 
  19         Modifications by Wolfgang Walter
  20                 Use dev_close cleanly so we always shut things down tidily.
  21 */
  22 
  23 #include <linux/config.h>
  24 #include <linux/kernel.h>
  25 #include <linux/sched.h>
  26 #include <linux/types.h>
  27 #include <linux/fs.h>
  28 #include <linux/malloc.h>
  29 #include <linux/if_ether.h>
  30 #include <linux/if_arp.h>
  31 #include <linux/string.h>
  32 #include <linux/netdevice.h>
  33 #include <linux/etherdevice.h>
  34 #include <linux/trdevice.h>
  35 
  36 /* The network devices currently exist only in the socket namespace, so these
  37    entries are unused.  The only ones that make sense are
  38     open        start the ethercard
  39     close       stop  the ethercard
  40     ioctl       To get statistics, perhaps set the interface port (AUI, BNC, etc.)
  41    One can also imagine getting raw packets using
  42     read & write
  43    but this is probably better handled by a raw packet socket.
  44 
  45    Given that almost all of these functions are handled in the current
  46    socket-based scheme, putting ethercard devices in /dev/ seems pointless.
  47    
  48    [Removed all support for /dev network devices. When someone adds
  49     streams then by magic we get them, but otherwise they are un-needed
  50         and a space waste]
  51 */
  52 
  53 /* The list of used and available "eth" slots (for "eth0", "eth1", etc.) */
  54 #define MAX_ETH_CARDS 16 /* same as the number if irq's in irq2dev[] */
  55 static struct device *ethdev_index[MAX_ETH_CARDS];
  56 
  57 
  58 /* Fill in the fields of the device structure with ethernet-generic values.
  59 
  60    If no device structure is passed, a new one is constructed, complete with
  61    a SIZEOF_PRIVATE private data area.
  62 
  63    If an empty string area is passed as dev->name, or a new structure is made,
  64    a new name string is constructed.  The passed string area should be 8 bytes
  65    long.
  66  */
  67 
  68 struct device *
  69 init_etherdev(struct device *dev, int sizeof_priv)
     /* [previous][next][first][last][top][bottom][index][help] */
  70 {
  71         int new_device = 0;
  72         int i;
  73 
  74         /* Use an existing correctly named device in Space.c:dev_base. */
  75         if (dev == NULL) {
  76                 int alloc_size = sizeof(struct device) + sizeof("eth%d  ")
  77                         + sizeof_priv + 3;
  78                 struct device *cur_dev;
  79                 char pname[8];          /* Putative name for the device.  */
  80 
  81                 for (i = 0; i < MAX_ETH_CARDS; ++i)
  82                         if (ethdev_index[i] == NULL) {
  83                                 sprintf(pname, "eth%d", i);
  84                                 for (cur_dev = dev_base; cur_dev; cur_dev = cur_dev->next)
  85                                         if (strcmp(pname, cur_dev->name) == 0) {
  86                                                 dev = cur_dev;
  87                                                 dev->init = NULL;
  88                                                 sizeof_priv = (sizeof_priv + 3) & ~3;
  89                                                 dev->priv = sizeof_priv
  90                                                           ? kmalloc(sizeof_priv, GFP_KERNEL)
  91                                                           :     NULL;
  92                                                 if (dev->priv) memset(dev->priv, 0, sizeof_priv);
  93                                                 goto found;
  94                                         }
  95                         }
  96 
  97                 alloc_size &= ~3;               /* Round to dword boundary. */
  98 
  99                 dev = (struct device *)kmalloc(alloc_size, GFP_KERNEL);
 100                 memset(dev, 0, alloc_size);
 101                 if (sizeof_priv)
 102                         dev->priv = (void *) (dev + 1);
 103                 dev->name = sizeof_priv + (char *)(dev + 1);
 104                 new_device = 1;
 105         }
 106 
 107         found:                                          /* From the double loop above. */
 108 
 109         if (dev->name &&
 110                 ((dev->name[0] == '\0') || (dev->name[0] == ' '))) {
 111                 for (i = 0; i < MAX_ETH_CARDS; ++i)
 112                         if (ethdev_index[i] == NULL) {
 113                                 sprintf(dev->name, "eth%d", i);
 114                                 ethdev_index[i] = dev;
 115                                 break;
 116                         }
 117         }
 118 
 119         ether_setup(dev);       /* Hmmm, should this be called here? */
 120         
 121         if (new_device) {
 122                 /* Append the device to the device queue. */
 123                 struct device **old_devp = &dev_base;
 124                 while ((*old_devp)->next)
 125                         old_devp = & (*old_devp)->next;
 126                 (*old_devp)->next = dev;
 127                 dev->next = 0;
 128         }
 129         return dev;
 130 }
 131 
 132 
 133 static int eth_mac_addr(struct device *dev, void * addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 134 {
 135         struct ifreq * ifr = (struct ifreq *) addr;
 136 
 137         if(dev->start)
 138                 return -EBUSY;
 139         memcpy(dev->dev_addr, ifr->ifr_hwaddr.sa_data,dev->hard_header_len);
 140         return 0;
 141 }
 142 
 143 void ether_setup(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 144 {
 145         int i;
 146         /* Fill in the fields of the device structure with ethernet-generic values.
 147            This should be in a common file instead of per-driver.  */
 148         for (i = 0; i < DEV_NUMBUFFS; i++)
 149                 skb_queue_head_init(&dev->buffs[i]);
 150 
 151         /* register boot-defined "eth" devices */
 152         if (dev->name && (strncmp(dev->name, "eth", 3) == 0)) {
 153                 i = simple_strtoul(dev->name + 3, NULL, 0);
 154                 if (ethdev_index[i] == NULL) {
 155                         ethdev_index[i] = dev;
 156                 }
 157                 else if (dev != ethdev_index[i]) {
 158                         /* Really shouldn't happen! */
 159                         printk("ether_setup: Ouch! Someone else took %s\n",
 160                                 dev->name);
 161                 }
 162         }
 163 
 164         dev->hard_header        = eth_header;
 165         dev->rebuild_header = eth_rebuild_header;
 166         dev->set_mac_address = eth_mac_addr;
 167         dev->header_cache = eth_header_cache;
 168 
 169         dev->type               = ARPHRD_ETHER;
 170         dev->hard_header_len = ETH_HLEN;
 171         dev->mtu                = 1500; /* eth_mtu */
 172         dev->addr_len   = ETH_ALEN;
 173         for (i = 0; i < ETH_ALEN; i++) {
 174                 dev->broadcast[i]=0xff;
 175         }
 176 
 177         /* New-style flags. */
 178         dev->flags              = IFF_BROADCAST|IFF_MULTICAST;
 179         dev->family             = AF_INET;
 180         dev->pa_addr    = 0;
 181         dev->pa_brdaddr = 0;
 182         dev->pa_mask    = 0;
 183         dev->pa_alen    = 4;
 184 }
 185 
 186 #ifdef CONFIG_TR
 187 
 188 void tr_setup(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 189 {
 190         int i;
 191         /* Fill in the fields of the device structure with ethernet-generic values.
 192            This should be in a common file instead of per-driver.  */
 193         for (i = 0; i < DEV_NUMBUFFS; i++)
 194                 skb_queue_head_init(&dev->buffs[i]);
 195 
 196         dev->hard_header        = tr_header;
 197         dev->rebuild_header = tr_rebuild_header;
 198 
 199         dev->type               = ARPHRD_IEEE802;
 200         dev->hard_header_len = TR_HLEN;
 201         dev->mtu                = 2000; /* bug in fragmenter...*/
 202         dev->addr_len   = TR_ALEN;
 203         for (i = 0; i < TR_ALEN; i++) {
 204                 dev->broadcast[i]=0xff;
 205         }
 206 
 207         /* New-style flags. */
 208         dev->flags              = IFF_BROADCAST;
 209         dev->family             = AF_INET;
 210         dev->pa_addr    = 0;
 211         dev->pa_brdaddr = 0;
 212         dev->pa_mask    = 0;
 213         dev->pa_alen    = 4;
 214 }
 215 
 216 #endif
 217 
 218 int ether_config(struct device *dev, struct ifmap *map)
     /* [previous][next][first][last][top][bottom][index][help] */
 219 {
 220         if (map->mem_start != (u_long)(-1))
 221                 dev->mem_start = map->mem_start;
 222         if (map->mem_end != (u_long)(-1))
 223                 dev->mem_end = map->mem_end;
 224         if (map->base_addr != (u_short)(-1))
 225                 dev->base_addr = map->base_addr;
 226         if (map->irq != (u_char)(-1))
 227                 dev->irq = map->irq;
 228         if (map->dma != (u_char)(-1))
 229                 dev->dma = map->dma;
 230         if (map->port != (u_char)(-1))
 231                 dev->if_port = map->port;
 232         return 0;
 233 }
 234 
 235 int register_netdev(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 236 {
 237         struct device *d = dev_base;
 238         unsigned long flags;
 239         int i=MAX_ETH_CARDS;
 240 
 241         save_flags(flags);
 242         cli();
 243 
 244         if (dev && dev->init) {
 245                 if (dev->name &&
 246                         ((dev->name[0] == '\0') || (dev->name[0] == ' '))) {
 247                         for (i = 0; i < MAX_ETH_CARDS; ++i)
 248                                 if (ethdev_index[i] == NULL) {
 249                                         sprintf(dev->name, "eth%d", i);
 250                                         ethdev_index[i] = dev;
 251                                         break;
 252                                 }
 253                 }
 254 
 255                 if (dev->init(dev) != 0) {
 256                     if (i < MAX_ETH_CARDS) ethdev_index[i] = NULL;
 257                         restore_flags(flags);
 258                         return -EIO;
 259                 }
 260 
 261                 /* Add device to end of chain */
 262                 if (dev_base) {
 263                         while (d->next)
 264                                 d = d->next;
 265                         d->next = dev;
 266                 }
 267                 else
 268                         dev_base = dev;
 269                 dev->next = NULL;
 270         }
 271         restore_flags(flags);
 272         return 0;
 273 }
 274 
 275 void unregister_netdev(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 276 {
 277         struct device *d = dev_base;
 278         unsigned long flags;
 279         int i;
 280 
 281         save_flags(flags);
 282         cli();
 283 
 284         if (dev == NULL) 
 285         {
 286                 printk("was NULL\n");
 287                 restore_flags(flags);
 288                 return;
 289         }
 290         /* else */
 291         if (dev->start)
 292                 printk("ERROR '%s' busy and not MOD_IN_USE.\n", dev->name);
 293         if (dev_base == dev)
 294                 dev_base = dev->next;
 295         else 
 296         {
 297                 while (d && (d->next != dev))
 298                         d = d->next;
 299                         
 300                 if (d && (d->next == dev)) 
 301                 {
 302                         d->next = dev->next;
 303                 }
 304                 else 
 305                 {
 306                         printk("unregister_netdev: '%s' not found\n", dev->name);
 307                         restore_flags(flags);
 308                         return;
 309                 }
 310         }
 311         for (i = 0; i < MAX_ETH_CARDS; ++i) 
 312         {
 313                 if (ethdev_index[i] == dev) 
 314                 {
 315                         ethdev_index[i] = NULL;
 316                         break;
 317                 }
 318         }
 319         /* You can i.e use a interfaces in a route though it is not up.
 320            We call close_dev (which is changed: it will down a device even if
 321            dev->flags==0 (but it will not call dev->stop if IFF_UP
 322            is not set).
 323            This will call notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev),
 324            dev_mc_discard(dev), ....
 325         */
 326         dev_close(dev);
 327 
 328         restore_flags(flags);
 329 }
 330 
 331 
 332 
 333 /*
 334  * Local variables:
 335  *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c net_init.c"
 336  *  version-control: t
 337  *  kept-new-versions: 5
 338  *  tab-width: 4
 339  * End:
 340  */

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