diff options
author | Zheng Da <zhengda1936@gmail.com> | 2009-11-14 00:15:08 +0100 |
---|---|---|
committer | Zheng Da <zhengda1936@gmail.com> | 2009-11-14 00:15:08 +0100 |
commit | 6c25f97b8e9171eb399d56549cded82d29d05924 (patch) | |
tree | d4870807926dcba2a27fb55f705f8af1424d77b1 /pcnet32/net_init.c | |
parent | ea13a76596f0a980fad58b83a6b50917d65b67c0 (diff) |
A working user-level pcnet32 driver.user-level_pcnet32
Diffstat (limited to 'pcnet32/net_init.c')
-rw-r--r-- | pcnet32/net_init.c | 450 |
1 files changed, 450 insertions, 0 deletions
diff --git a/pcnet32/net_init.c b/pcnet32/net_init.c new file mode 100644 index 000000000..f375c2ab0 --- /dev/null +++ b/pcnet32/net_init.c @@ -0,0 +1,450 @@ +/* netdrv_init.c: Initialization for network devices. */ +/* + Written 1993,1994,1995 by Donald Becker. + + The author may be reached as becker@cesdis.gsfc.nasa.gov or + C/O Center of Excellence in Space Data and Information Sciences + Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + + This file contains the initialization for the "pl14+" style ethernet + drivers. It should eventually replace most of drivers/net/Space.c. + It's primary advantage is that it's able to allocate low-memory buffers. + A secondary advantage is that the dangerous NE*000 netcards can reserve + their I/O port region before the SCSI probes start. + + Modifications/additions by Bjorn Ekwall <bj0rn@blox.se>: + ethdev_index[MAX_ETH_CARDS] + register_netdev() / unregister_netdev() + + Modifications by Wolfgang Walter + Use dev_close cleanly so we always shut things down tidily. + + Changed 29/10/95, Alan Cox to pass sockaddr's around for mac addresses. + + 14/06/96 - Paul Gortmaker: Add generic eth_change_mtu() function. + + August 12, 1996 - Lawrence V. Stefani: Added fddi_change_mtu() and + fddi_setup() functions. + Sept. 10, 1996 - Lawrence V. Stefani: Increased hard_header_len to + include 3 pad bytes. +*/ + +/* The network devices currently exist only in the socket namespace, so these + entries are unused. The only ones that make sense are + open start the ethercard + close stop the ethercard + ioctl To get statistics, perhaps set the interface port (AUI, BNC, etc.) + One can also imagine getting raw packets using + read & write + but this is probably better handled by a raw packet socket. + + Given that almost all of these functions are handled in the current + socket-based scheme, putting ethercard devices in /dev/ seems pointless. + + [Removed all support for /dev network devices. When someone adds + streams then by magic we get them, but otherwise they are un-needed + and a space waste] +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> + +#include "if.h" +#include "if_arp.h" +#include "if_ether.h" +#include "netdevice.h" +#include "util.h" + +/* The list of used and available "eth" slots (for "eth0", "eth1", etc.) */ +#define MAX_ETH_CARDS 16 /* same as the number if irq's in irq2dev[] */ +static struct device *ethdev_index[MAX_ETH_CARDS]; + +struct device *dev_base; + +struct port_class *intr_class; +struct port_bucket *irq_port_bucket; + + +/* Fill in the fields of the device structure with ethernet-generic values. + + If no device structure is passed, a new one is constructed, complete with + a SIZEOF_PRIVATE private data area. + + If an empty string area is passed as dev->name, or a new structure is made, + a new name string is constructed. The passed string area should be 8 bytes + long. + */ + +struct device * +init_etherdev(struct device *dev, int sizeof_priv) +{ + int new_device = 0; + int i; + + /* Use an existing correctly named device in Space.c:dev_base. */ + if (dev == NULL) { + int alloc_size = sizeof(struct device) + sizeof("eth%d ") + + sizeof_priv + 3; + struct device *cur_dev; + char pname[8]; /* Putative name for the device. */ + + for (i = 0; i < MAX_ETH_CARDS; ++i) + if (ethdev_index[i] == NULL) { + sprintf(pname, "eth%d", i); + for (cur_dev = dev_base; cur_dev; cur_dev = cur_dev->next) + if (strcmp(pname, cur_dev->name) == 0) { + dev = cur_dev; + dev->init = NULL; + sizeof_priv = (sizeof_priv + 3) & ~3; + dev->priv = sizeof_priv + ? malloc(sizeof_priv) + : NULL; + if (dev->priv) memset(dev->priv, 0, sizeof_priv); + goto found; + } + } + + alloc_size &= ~3; /* Round to dword boundary. */ + + ports_create_port (intr_class, irq_port_bucket, + sizeof (struct port_info) + alloc_size, &dev); + memset(((struct port_info *) dev) + 1, 0, alloc_size); + if (sizeof_priv) + dev->priv = (void *) (dev + 1); + dev->name = sizeof_priv + (char *)(dev + 1); + new_device = 1; + } + + found: /* From the double loop above. */ + + if (dev->name && + ((dev->name[0] == '\0') || (dev->name[0] == ' '))) { + for (i = 0; i < MAX_ETH_CARDS; ++i) + if (ethdev_index[i] == NULL) { + sprintf(dev->name, "eth%d", i); + debug ("setup device %s", dev->name); + ethdev_index[i] = dev; + break; + } + } + + ether_setup(dev); /* Hmmm, should this be called here? */ + + if (new_device) { + /* Append the device to the device queue. */ + struct device **old_devp = &dev_base; + if (*old_devp == NULL) + *old_devp = dev; + while ((*old_devp)->next) + old_devp = & (*old_devp)->next; + (*old_devp)->next = dev; + dev->next = 0; + } + return dev; +} + + +//static int eth_mac_addr(struct device *dev, void *p) +//{ +// struct sockaddr *addr=p; +// if(dev->start) +// return -EBUSY; +// memcpy(dev->dev_addr, addr->sa_data,dev->addr_len); +// return 0; +//} +// +//static int eth_change_mtu(struct device *dev, int new_mtu) +//{ +// if ((new_mtu < 68) || (new_mtu > 1500)) +// return -EINVAL; +// dev->mtu = new_mtu; +// return 0; +//} + +#ifdef CONFIG_FDDI + +static int fddi_change_mtu(struct device *dev, int new_mtu) +{ + if ((new_mtu < FDDI_K_SNAP_HLEN) || (new_mtu > FDDI_K_SNAP_DLEN)) + return(-EINVAL); + dev->mtu = new_mtu; + return(0); +} + +#endif + +void ether_setup(struct device *dev) +{ + int i; + /* Fill in the fields of the device structure with ethernet-generic values. + This should be in a common file instead of per-driver. */ + for (i = 0; i < DEV_NUMBUFFS; i++) + skb_queue_head_init(&dev->buffs[i]); + + /* register boot-defined "eth" devices */ + if (dev->name && (strncmp(dev->name, "eth", 3) == 0)) { +// i = simple_strtoul(dev->name + 3, NULL, 0); + i = strtoul(dev->name + 3, NULL, 0); + if (ethdev_index[i] == NULL) { + ethdev_index[i] = dev; + } + else if (dev != ethdev_index[i]) { + /* Really shouldn't happen! */ +#ifdef MACH + panic("ether_setup: Ouch! Someone else took %s\n", + dev->name); +#else + printk("ether_setup: Ouch! Someone else took %s\n", + dev->name); +#endif + } + } + +#ifndef MACH + dev->change_mtu = eth_change_mtu; + dev->hard_header = eth_header; + dev->rebuild_header = eth_rebuild_header; + dev->set_mac_address = eth_mac_addr; + dev->header_cache_bind = eth_header_cache_bind; + dev->header_cache_update= eth_header_cache_update; +#endif + + dev->type = ARPHRD_ETHER; + dev->hard_header_len = ETH_HLEN; + dev->mtu = 1500; /* eth_mtu */ + dev->addr_len = ETH_ALEN; + dev->tx_queue_len = 100; /* Ethernet wants good queues */ + + memset(dev->broadcast,0xFF, ETH_ALEN); + + /* New-style flags. */ + dev->flags = IFF_BROADCAST|IFF_MULTICAST; + dev->family = AF_INET; + dev->pa_addr = 0; + dev->pa_brdaddr = 0; + dev->pa_mask = 0; + dev->pa_alen = 4; +} + +#ifdef CONFIG_TR + +void tr_setup(struct device *dev) +{ + int i; + /* Fill in the fields of the device structure with ethernet-generic values. + This should be in a common file instead of per-driver. */ + for (i = 0; i < DEV_NUMBUFFS; i++) + skb_queue_head_init(&dev->buffs[i]); + + dev->hard_header = tr_header; + dev->rebuild_header = tr_rebuild_header; + + dev->type = ARPHRD_IEEE802; + dev->hard_header_len = TR_HLEN; + dev->mtu = 2000; /* bug in fragmenter...*/ + dev->addr_len = TR_ALEN; + dev->tx_queue_len = 100; /* Long queues on tr */ + + memset(dev->broadcast,0xFF, TR_ALEN); + + /* New-style flags. */ + dev->flags = IFF_BROADCAST; + dev->family = AF_INET; + dev->pa_addr = 0; + dev->pa_brdaddr = 0; + dev->pa_mask = 0; + dev->pa_alen = 4; +} + +#endif + +#ifdef CONFIG_FDDI + +void fddi_setup(struct device *dev) + { + int i; + + /* + * Fill in the fields of the device structure with FDDI-generic values. + * This should be in a common file instead of per-driver. + */ + for (i=0; i < DEV_NUMBUFFS; i++) + skb_queue_head_init(&dev->buffs[i]); + + dev->change_mtu = fddi_change_mtu; + dev->hard_header = fddi_header; + dev->rebuild_header = fddi_rebuild_header; + + dev->type = ARPHRD_FDDI; + dev->hard_header_len = FDDI_K_SNAP_HLEN+3; /* Assume 802.2 SNAP hdr len + 3 pad bytes */ + dev->mtu = FDDI_K_SNAP_DLEN; /* Assume max payload of 802.2 SNAP frame */ + dev->addr_len = FDDI_K_ALEN; + dev->tx_queue_len = 100; /* Long queues on FDDI */ + + memset(dev->broadcast, 0xFF, FDDI_K_ALEN); + + /* New-style flags */ + dev->flags = IFF_BROADCAST | IFF_MULTICAST; + dev->family = AF_INET; + dev->pa_addr = 0; + dev->pa_brdaddr = 0; + dev->pa_mask = 0; + dev->pa_alen = 4; + return; + } + +#endif + +int ether_config(struct device *dev, struct ifmap *map) +{ + if (map->mem_start != (u_long)(-1)) + dev->mem_start = map->mem_start; + if (map->mem_end != (u_long)(-1)) + dev->mem_end = map->mem_end; + if (map->base_addr != (u_short)(-1)) + dev->base_addr = map->base_addr; + if (map->irq != (u_char)(-1)) + dev->irq = map->irq; + if (map->dma != (u_char)(-1)) + dev->dma = map->dma; + if (map->port != (u_char)(-1)) + dev->if_port = map->port; + return 0; +} + +//int register_netdev(struct device *dev) +//{ +// struct device *d = dev_base; +// unsigned long flags; +// int i=MAX_ETH_CARDS; +// +// save_flags(flags); +// cli(); +// +// if (dev && dev->init) { +// if (dev->name && +// ((dev->name[0] == '\0') || (dev->name[0] == ' '))) { +// for (i = 0; i < MAX_ETH_CARDS; ++i) +// if (ethdev_index[i] == NULL) { +// sprintf(dev->name, "eth%d", i); +// printk("loading device '%s'...\n", dev->name); +// ethdev_index[i] = dev; +// break; +// } +// } +// +// sti(); /* device probes assume interrupts enabled */ +// if (dev->init(dev) != 0) { +// if (i < MAX_ETH_CARDS) ethdev_index[i] = NULL; +// restore_flags(flags); +// return -EIO; +// } +// cli(); +// +// /* Add device to end of chain */ +// if (dev_base) { +// while (d->next) +// d = d->next; +// d->next = dev; +// } +// else +// dev_base = dev; +// dev->next = NULL; +// } +// restore_flags(flags); +// return 0; +//} +// +//void unregister_netdev(struct device *dev) +//{ +// struct device *d = dev_base; +// unsigned long flags; +// int i; +// +// save_flags(flags); +// cli(); +// +// if (dev == NULL) +// { +// printk("was NULL\n"); +// restore_flags(flags); +// return; +// } +// /* else */ +// if (dev->start) +// printk("ERROR '%s' busy and not MOD_IN_USE.\n", dev->name); +// +// /* +// * must jump over main_device+aliases +// * avoid alias devices unregistration so that only +// * net_alias module manages them +// */ +//#ifdef CONFIG_NET_ALIAS +// if (dev_base == dev) +// dev_base = net_alias_nextdev(dev); +// else +// { +// while(d && (net_alias_nextdev(d) != dev)) /* skip aliases */ +// d = net_alias_nextdev(d); +// +// if (d && (net_alias_nextdev(d) == dev)) +// { +// /* +// * Critical: Bypass by consider devices as blocks (maindev+aliases) +// */ +// net_alias_nextdev_set(d, net_alias_nextdev(dev)); +// } +//#else +// if (dev_base == dev) +// dev_base = dev->next; +// else +// { +// while (d && (d->next != dev)) +// d = d->next; +// +// if (d && (d->next == dev)) +// { +// d->next = dev->next; +// } +//#endif +// else +// { +// printk("unregister_netdev: '%s' not found\n", dev->name); +// restore_flags(flags); +// return; +// } +// } +// for (i = 0; i < MAX_ETH_CARDS; ++i) +// { +// if (ethdev_index[i] == dev) +// { +// ethdev_index[i] = NULL; +// break; +// } +// } +// +// restore_flags(flags); +// +// /* +// * You can i.e use a interfaces in a route though it is not up. +// * We call close_dev (which is changed: it will down a device even if +// * dev->flags==0 (but it will not call dev->stop if IFF_UP +// * is not set). +// * This will call notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev), +// * dev_mc_discard(dev), .... +// */ +// +// dev_close(dev); +//} + + +/* + * Local variables: + * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c net_init.c" + * version-control: t + * kept-new-versions: 5 + * tab-width: 4 + * End: + */ |