Commit 9e11983a authored by Linus Torvalds's avatar Linus Torvalds

Import 0.99.15f

parent 350827b4
...@@ -160,6 +160,7 @@ function int () { ...@@ -160,6 +160,7 @@ function int () {
CONFIG=.config~ CONFIG=.config~
CONFIG_H=include/linux/autoconf.h CONFIG_H=include/linux/autoconf.h
trap "rm -f $CONFIG $CONFIG_H config.new ; exit 1" 1 2
# #
# Make sure we start out with a clean slate. # Make sure we start out with a clean slate.
......
VERSION = 0.99 VERSION = 0.99
PATCHLEVEL = 15 PATCHLEVEL = 15
ALPHA = e ALPHA = f
all: Version zImage all: Version zImage
......
...@@ -442,7 +442,6 @@ unsigned long psaux_init(unsigned long kmem_start) ...@@ -442,7 +442,6 @@ unsigned long psaux_init(unsigned long kmem_start)
int qp_found = 0; int qp_found = 0;
#ifdef CONFIG_82C710_MOUSE #ifdef CONFIG_82C710_MOUSE
printk("Probing 82C710 mouse port device.\n");
if ((qp_found = probe_qp())) { if ((qp_found = probe_qp())) {
printk("82C710 type pointing device detected -- driver installed.\n"); printk("82C710 type pointing device detected -- driver installed.\n");
/* printk("82C710 address = %x (should be 0x310)\n", qp_data); */ /* printk("82C710 address = %x (should be 0x310)\n", qp_data); */
......
...@@ -1528,11 +1528,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) ...@@ -1528,11 +1528,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
tty->hw_stopped = 0; tty->hw_stopped = 0;
if (info->flags & ASYNC_INITIALIZED) { if (info->flags & ASYNC_INITIALIZED) {
rs_start(tty); rs_start(tty);
/* wait_until_sent(tty, 6000); /* 60 seconds timeout */
* XXX There should be a timeout added to
* wait_until_sent, eventually. TYT 1/19/94
*/
wait_until_sent(tty);
} else } else
flush_output(tty); flush_output(tty);
flush_input(tty); flush_input(tty);
......
...@@ -82,7 +82,7 @@ void flush_output(struct tty_struct * tty) ...@@ -82,7 +82,7 @@ void flush_output(struct tty_struct * tty)
} }
} }
void wait_until_sent(struct tty_struct * tty) void wait_until_sent(struct tty_struct * tty, int timeout)
{ {
struct wait_queue wait = { current, NULL }; struct wait_queue wait = { current, NULL };
...@@ -91,7 +91,11 @@ void wait_until_sent(struct tty_struct * tty) ...@@ -91,7 +91,11 @@ void wait_until_sent(struct tty_struct * tty)
return; return;
add_wait_queue(&tty->write_q.proc_list, &wait); add_wait_queue(&tty->write_q.proc_list, &wait);
current->counter = 0; /* make us low-priority */ current->counter = 0; /* make us low-priority */
while (1) { if (timeout)
current->timeout = timeout + jiffies;
else
current->timeout = (unsigned) -1;
do {
current->state = TASK_INTERRUPTIBLE; current->state = TASK_INTERRUPTIBLE;
if (current->signal & ~current->blocked) if (current->signal & ~current->blocked)
break; break;
...@@ -99,7 +103,7 @@ void wait_until_sent(struct tty_struct * tty) ...@@ -99,7 +103,7 @@ void wait_until_sent(struct tty_struct * tty)
if (EMPTY(&tty->write_q)) if (EMPTY(&tty->write_q))
break; break;
schedule(); schedule();
} } while (current->timeout);
current->state = TASK_RUNNING; current->state = TASK_RUNNING;
remove_wait_queue(&tty->write_q.proc_list, &wait); remove_wait_queue(&tty->write_q.proc_list, &wait);
} }
...@@ -297,7 +301,7 @@ static int tty_set_ldisc(struct tty_struct *tty, int ldisc) ...@@ -297,7 +301,7 @@ static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
return 0; /* We are already in the desired discipline */ return 0; /* We are already in the desired discipline */
/* Shutdown the current discipline. */ /* Shutdown the current discipline. */
wait_until_sent(tty); wait_until_sent(tty, 0);
flush_input(tty); flush_input(tty);
if (ldiscs[tty->disc].close) if (ldiscs[tty->disc].close)
ldiscs[tty->disc].close(tty); ldiscs[tty->disc].close(tty);
...@@ -379,7 +383,7 @@ int tty_ioctl(struct inode * inode, struct file * file, ...@@ -379,7 +383,7 @@ int tty_ioctl(struct inode * inode, struct file * file,
if (cmd == TCSETSF || cmd == TCSETSW) { if (cmd == TCSETSF || cmd == TCSETSW) {
if (cmd == TCSETSF) if (cmd == TCSETSF)
flush_input(termios_tty); flush_input(termios_tty);
wait_until_sent(termios_tty); wait_until_sent(termios_tty, 0);
} }
return set_termios(termios_tty, (struct termios *) arg, return set_termios(termios_tty, (struct termios *) arg,
termios_dev); termios_dev);
...@@ -394,7 +398,7 @@ int tty_ioctl(struct inode * inode, struct file * file, ...@@ -394,7 +398,7 @@ int tty_ioctl(struct inode * inode, struct file * file,
if (cmd == TCSETAF || cmd == TCSETAW) { if (cmd == TCSETAF || cmd == TCSETAW) {
if (cmd == TCSETAF) if (cmd == TCSETAF)
flush_input(termios_tty); flush_input(termios_tty);
wait_until_sent(termios_tty); wait_until_sent(termios_tty, 0);
} }
return set_termio(termios_tty, (struct termio *) arg, return set_termio(termios_tty, (struct termio *) arg,
termios_dev); termios_dev);
...@@ -642,7 +646,7 @@ int tty_ioctl(struct inode * inode, struct file * file, ...@@ -642,7 +646,7 @@ int tty_ioctl(struct inode * inode, struct file * file,
retval = check_change(tty, dev); retval = check_change(tty, dev);
if (retval) if (retval)
return retval; return retval;
wait_until_sent(tty); wait_until_sent(tty, 0);
if (!tty->ioctl) if (!tty->ioctl)
return 0; return 0;
tty->ioctl(tty, file, cmd, arg); tty->ioctl(tty, file, cmd, arg);
......
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
Thanks go to jennings@Montrouge.SMR.slb.com ( Patrick Jennings) Thanks go to jennings@Montrouge.SMR.slb.com ( Patrick Jennings)
and jrs@world.std.com (Rick Sladkey) for testing and bugfixes. and jrs@world.std.com (Rick Sladkey) for testing and bugfixes.
Mark Salazar <leslie@access.digex.net> made the changes for cards with
only 16K packet buffers.
Things remaining to do: Things remaining to do:
Verify that the tx and rx buffers don't have fencepost errors. Verify that the tx and rx buffers don't have fencepost errors.
...@@ -19,7 +21,7 @@ ...@@ -19,7 +21,7 @@
*/ */
static char *version = static char *version =
"3c507.c:v0.03 10/27/93 Donald Becker (becker@super.org)\n"; "3c507.c:v0.99-15f 2/17/94 Donald Becker (becker@super.org)\n";
#include <linux/config.h> #include <linux/config.h>
...@@ -145,6 +147,17 @@ struct net_local { ...@@ -145,6 +147,17 @@ struct net_local {
#define iSCB_CBL 0xC /* Command BLock offset. */ #define iSCB_CBL 0xC /* Command BLock offset. */
#define iSCB_RFA 0xE /* Rx Frame Area offset. */ #define iSCB_RFA 0xE /* Rx Frame Area offset. */
/* Since the 3c507 maps the shared memory window so that the last byte is
at 82586 address FFFF, the first byte is at 82586 address 0, 16K, 32K, or
48K cooresponding to window sizes of 64K, 48K, 32K and 16K respectively.
We can account for this be setting the 'SBC Base' entry in the ISCP table
below for all the 16 bit offset addresses, and also adding the 'SCB Base'
value to all 24 bit physical addresses (in the SCP table and the TX and RX
Buffer Descriptors).
-Mark
*/
#define SCB_BASE ((unsigned)64*1024 - (dev->mem_end - dev->mem_start))
/* /*
What follows in 'init_words[]' is the "program" that is downloaded to the What follows in 'init_words[]' is the "program" that is downloaded to the
82586 memory. It's mostly tables and command blocks, and starts at the 82586 memory. It's mostly tables and command blocks, and starts at the
...@@ -192,7 +205,7 @@ struct net_local { ...@@ -192,7 +205,7 @@ struct net_local {
The Tx command chain and buffer list is setup as follows: The Tx command chain and buffer list is setup as follows:
A Tx command table, with the data buffer pointing to... A Tx command table, with the data buffer pointing to...
A Tx data buffer descriptor. The packet is in a single buffer, rather than A Tx data buffer descriptor. The packet is in a single buffer, rather than
chaining together several smaller buffers. chaining together several smaller buffers.
A NoOp command, which initially points to itself, A NoOp command, which initially points to itself,
And the packet data. And the packet data.
...@@ -213,13 +226,17 @@ struct net_local { ...@@ -213,13 +226,17 @@ struct net_local {
*/ */
short init_words[] = { unsigned short init_words[] = {
/* System Configuration Pointer (SCP). */
0x0000, /* Set bus size to 16 bits. */ 0x0000, /* Set bus size to 16 bits. */
0x0000,0x0000, /* Set control mailbox (SCB) addr. */ 0,0, /* pad words. */
0,0, /* pad to 0x000000. */ 0x0000,0x0000, /* ISCP phys addr, set in init_82586_mem(). */
/* Intermediate System Configuration Pointer (ISCP). */
0x0001, /* Status word that's cleared when init is done. */ 0x0001, /* Status word that's cleared when init is done. */
0x0008,0,0, /* SCB offset, (skip, skip) */ 0x0008,0,0, /* SCB offset, (skip, skip) */
/* System Control Block (SCB). */
0,0xf000|RX_START|CUC_START, /* SCB status and cmd. */ 0,0xf000|RX_START|CUC_START, /* SCB status and cmd. */
CONFIG_CMD, /* Command list pointer, points to Configure. */ CONFIG_CMD, /* Command list pointer, points to Configure. */
RX_BUF_START, /* Rx block list. */ RX_BUF_START, /* Rx block list. */
...@@ -270,11 +287,11 @@ void init_82586_mem(struct device *dev); ...@@ -270,11 +287,11 @@ void init_82586_mem(struct device *dev);
/* Check for a network adaptor of this type, and return '0' iff one exists. /* Check for a network adaptor of this type, and return '0' iff one exists.
If dev->base_addr == 0, probe all likely locations. If dev->base_addr == 0, probe all likely locations.
If dev->base_addr == 1, always return failure. If dev->base_addr == 1, always return failure.
If dev->base_addr == 2, (detachable devices only) alloate space for the If dev->base_addr == 2, (detachable devices only) alloate space for the
device and return success. device and return success.
*/ */
int int
el16_probe(struct device *dev) el16_probe(struct device *dev)
{ {
...@@ -369,9 +386,6 @@ int el16_probe1(struct device *dev, short ioaddr) ...@@ -369,9 +386,6 @@ int el16_probe1(struct device *dev, short ioaddr)
size = ((mem_config & 3) + 1) << 14; size = ((mem_config & 3) + 1) << 14;
base = 0x0c0000 + ( (mem_config & 0x18) << 12); base = 0x0c0000 + ( (mem_config & 0x18) << 12);
} }
if (size != 0x10000)
printk("%s: Warning, this version probably only works with 64K of"
"shared memory.\n", dev->name);
dev->mem_start = base; dev->mem_start = base;
dev->mem_end = base + size; dev->mem_end = base + size;
} }
...@@ -538,9 +552,9 @@ el16_interrupt(int reg_ptr) ...@@ -538,9 +552,9 @@ el16_interrupt(int reg_ptr)
status = shmem[iSCB_STATUS>>1]; status = shmem[iSCB_STATUS>>1];
if (net_debug > 4) { if (net_debug > 4) {
printk("%s: 3c507 interrupt, status %4.4x.\n", dev->name, status); printk("%s: 3c507 interrupt, status %4.4x.\n", dev->name, status);
} }
/* Disable the 82586's input to the interrupt line. */ /* Disable the 82586's input to the interrupt line. */
outb(0x80, ioaddr + MISC_CTRL); outb(0x80, ioaddr + MISC_CTRL);
...@@ -661,6 +675,7 @@ init_rx_bufs(struct device *dev) ...@@ -661,6 +675,7 @@ init_rx_bufs(struct device *dev)
{ {
struct net_local *lp = (struct net_local *)dev->priv; struct net_local *lp = (struct net_local *)dev->priv;
unsigned short *write_ptr; unsigned short *write_ptr;
unsigned short SCB_base = SCB_BASE;
int cur_rxbuf = lp->rx_head = RX_BUF_START; int cur_rxbuf = lp->rx_head = RX_BUF_START;
...@@ -683,7 +698,7 @@ init_rx_bufs(struct device *dev) ...@@ -683,7 +698,7 @@ init_rx_bufs(struct device *dev)
*write_ptr++ = 0x0000; /* Buffer: Actual count */ *write_ptr++ = 0x0000; /* Buffer: Actual count */
*write_ptr++ = -1; /* Buffer: Next (none). */ *write_ptr++ = -1; /* Buffer: Next (none). */
*write_ptr++ = cur_rxbuf + 0x20; /* Buffer: Address low */ *write_ptr++ = cur_rxbuf + 0x20 + SCB_base; /* Buffer: Address low */
*write_ptr++ = 0x0000; *write_ptr++ = 0x0000;
/* Finally, the number of bytes in the buffer. */ /* Finally, the number of bytes in the buffer. */
*write_ptr++ = 0x8000 + RX_BUF_SIZE-0x20; *write_ptr++ = 0x8000 + RX_BUF_SIZE-0x20;
...@@ -712,12 +727,13 @@ init_82586_mem(struct device *dev) ...@@ -712,12 +727,13 @@ init_82586_mem(struct device *dev)
and hold the 586 in reset during the memory initialization. */ and hold the 586 in reset during the memory initialization. */
outb(0x20, ioaddr + MISC_CTRL); outb(0x20, ioaddr + MISC_CTRL);
/* Fix the ISCP address and base. */
init_words[3] = SCB_BASE;
init_words[7] = SCB_BASE;
/* Write the words at 0xfff6 (address-aliased to 0xfffff6). */ /* Write the words at 0xfff6 (address-aliased to 0xfffff6). */
#ifdef old
memcpy((void*)dev->mem_start+0xfff6, init_words, 10);
#else
memcpy((void*)dev->mem_end-10, init_words, 10); memcpy((void*)dev->mem_end-10, init_words, 10);
#endif
/* Write the words at 0x0000. */ /* Write the words at 0x0000. */
memcpy((char*)dev->mem_start, init_words + 5, sizeof(init_words) - 10); memcpy((char*)dev->mem_start, init_words + 5, sizeof(init_words) - 10);
...@@ -776,7 +792,7 @@ hardware_send_packet(struct device *dev, void *buf, short length) ...@@ -776,7 +792,7 @@ hardware_send_packet(struct device *dev, void *buf, short length)
/* Output the data buffer descriptor. */ /* Output the data buffer descriptor. */
*write_ptr++ = length | 0x8000; /* Byte count parameter. */ *write_ptr++ = length | 0x8000; /* Byte count parameter. */
*write_ptr++ = -1; /* No next data buffer. */ *write_ptr++ = -1; /* No next data buffer. */
*write_ptr++ = tx_block+22; /* Buffer follows the NoOp command. */ *write_ptr++ = tx_block+22+SCB_BASE;/* Buffer follows the NoOp command. */
*write_ptr++ = 0x0000; /* Buffer address high bits (always zero). */ *write_ptr++ = 0x0000; /* Buffer address high bits (always zero). */
/* Output the Loop-back NoOp command. */ /* Output the Loop-back NoOp command. */
...@@ -796,10 +812,10 @@ hardware_send_packet(struct device *dev, void *buf, short length) ...@@ -796,10 +812,10 @@ hardware_send_packet(struct device *dev, void *buf, short length)
if (lp->tx_head > RX_BUF_START - TX_BUF_SIZE) if (lp->tx_head > RX_BUF_START - TX_BUF_SIZE)
lp->tx_head = TX_BUF_START; lp->tx_head = TX_BUF_START;
if (net_debug > 4) { if (net_debug > 4) {
printk("%s: 3c507 @%x send length = %d, tx_block %3x, next %3x.\n", printk("%s: 3c507 @%x send length = %d, tx_block %3x, next %3x.\n",
dev->name, ioaddr, length, tx_block, lp->tx_head); dev->name, ioaddr, length, tx_block, lp->tx_head);
} }
if (lp->tx_head != lp->tx_reap) if (lp->tx_head != lp->tx_reap)
dev->tbusy = 0; dev->tbusy = 0;
...@@ -893,6 +909,7 @@ el16_rx(struct device *dev) ...@@ -893,6 +909,7 @@ el16_rx(struct device *dev)
* version-control: t * version-control: t
* kept-new-versions: 5 * kept-new-versions: 5
* tab-width: 4 * tab-width: 4
* c-indent-level: 4
* End: * End:
*/ */
This diff is collapsed.
...@@ -145,8 +145,9 @@ static struct device atp_dev = { ...@@ -145,8 +145,9 @@ static struct device atp_dev = {
#ifndef ETH0_IRQ #ifndef ETH0_IRQ
# define ETH0_IRQ 0 # define ETH0_IRQ 0
#endif #endif
/* "eth0" defaults to autoprobe, other use a base of "-0x20", "don't probe". /* "eth0" defaults to autoprobe (== 0), other use a base of 0xffe0 (== -0x20),
Enable these with boot-time setup. 0.99pl13+ can optionally autoprobe. */ which means "don't probe". These entries exist to only to provide empty
slots which may be enabled at boot-time. */
static struct device eth3_dev = { static struct device eth3_dev = {
"eth3", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, NEXT_DEV, ethif_probe }; "eth3", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, NEXT_DEV, ethif_probe };
......
...@@ -12,13 +12,16 @@ ...@@ -12,13 +12,16 @@
*/ */
static char *version = static char *version =
"at1700.c:v0.03 11/16/93 Donald Becker (becker@super.org)\n"; "at1700.c:v0.05 2/9/94 Donald Becker (becker@super.org)\n";
#include <linux/config.h> #include <linux/config.h>
/* /*
Sources: Sources:
The Fujitsu MB86695 datasheet. The Fujitsu MB86695 datasheet.
After this driver was written, ATI provided their EEPROM configuration
code header file. Thanks to Gerry Sockins of ATI.
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -30,12 +33,12 @@ static char *version = ...@@ -30,12 +33,12 @@ static char *version =
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/in.h> #include <linux/in.h>
#include <linux/malloc.h> #include <linux/malloc.h>
#include <linux/string.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/bitops.h> #include <asm/bitops.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/dma.h> #include <asm/dma.h>
#include <errno.h> #include <errno.h>
#include <memory.h>
#include "dev.h" #include "dev.h"
#include "eth.h" #include "eth.h"
...@@ -142,24 +145,28 @@ at1700_probe(struct device *dev) ...@@ -142,24 +145,28 @@ at1700_probe(struct device *dev)
for (port = &ports[0]; *port; port++) { for (port = &ports[0]; *port; port++) {
int ioaddr = *port; int ioaddr = *port;
#ifdef HAVE_PORTRESERVE
if (check_region(ioaddr, 32)) if (check_region(ioaddr, 32))
continue; continue;
#endif
if (inw(ioaddr) != 0x0000)
continue;
if (at1700_probe1(dev, ioaddr) == 0) if (at1700_probe1(dev, ioaddr) == 0)
return 0; return 0;
} }
return ENODEV; /* ENODEV would be more accurate. */ return ENODEV;
} }
/* The Fujitsu datasheet suggests that the NIC be probed for by checking its
"signature", the default bit pattern after a reset. This *doesn't* work --
there is no way to reset the bus interface without a complete power-cycle!
It turns out that ATI came to the same conclusion I did: the only thing
that can be done is checking a few bits and then diving right into an
EEPROM read. */
int at1700_probe1(struct device *dev, short ioaddr) int at1700_probe1(struct device *dev, short ioaddr)
{ {
unsigned short signature[4] = {0x0000, 0xffff, 0x41f6, 0xefb6}; unsigned short signature[4] = {0xffff, 0xffff, 0x7ff7, 0xff5f};
unsigned short signature_invalid[4] = {0x0000, 0xffff, 0x00f0, 0x2f00}; unsigned short signature_invalid[4] = {0xffff, 0xffff, 0x7ff7, 0xdf0f};
char irqmap[4] = {3, 4, 5, 9}; char irqmap[8] = {3, 4, 5, 9, 10, 11, 14, 15};
unsigned short *station_address = (unsigned short *)dev->dev_addr; unsigned short *station_address = (unsigned short *)dev->dev_addr;
unsigned int i, irq; unsigned int i, irq;
...@@ -168,18 +175,21 @@ int at1700_probe1(struct device *dev, short ioaddr) ...@@ -168,18 +175,21 @@ int at1700_probe1(struct device *dev, short ioaddr)
*/ */
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
if ((inw(ioaddr + 2*i) | signature_invalid[i]) != signature[i]) { if ((inw(ioaddr + 2*i) | signature_invalid[i]) != signature[i]) {
if (net_debug > 1) if (net_debug > 2)
printk("AT1700 signature match failed at %d (%04x vs. %04x)\n", printk("AT1700 signature match failed at %d (%04x vs. %04x)\n",
i, inw(ioaddr + 2*i), signature[i]); i, inw(ioaddr + 2*i), signature[i]);
return -ENODEV; return -ENODEV;
} }
#ifdef HAVE_PORTRESERVE if (read_eeprom(ioaddr, 4) != 0x0000
|| read_eeprom(ioaddr, 5) & 0x00ff != 0x00F4)
return -ENODEV;
/* Grab the region so that we can find another board if the IRQ request /* Grab the region so that we can find another board if the IRQ request
fails. */ fails. */
snarf_region(ioaddr, 32); snarf_region(ioaddr, 32);
#endif
irq = irqmap[ read_eeprom(ioaddr, 0) >> 14 ]; irq = irqmap[(read_eeprom(ioaddr, 12)&0x04)
| (read_eeprom(ioaddr, 0)>>14)];
/* Snarf the interrupt vector now. */ /* Snarf the interrupt vector now. */
if (request_irq(irq, &net_interrupt)) { if (request_irq(irq, &net_interrupt)) {
...@@ -402,7 +412,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev) ...@@ -402,7 +412,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev)
/* For ethernet, fill in the header. This should really be done by a /* For ethernet, fill in the header. This should really be done by a
higher level, rather than duplicated for each ethernet adaptor. */ higher level, rather than duplicated for each ethernet adaptor. */
if (!skb->arp && dev->rebuild_header(skb->data, dev)) { if (!skb->arp && dev->rebuild_header(skb+1, dev)) {
skb->dev = dev; skb->dev = dev;
arp_queue (skb); arp_queue (skb);
return 0; return 0;
...@@ -415,7 +425,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev) ...@@ -415,7 +425,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev)
printk("%s: Transmitter access conflict.\n", dev->name); printk("%s: Transmitter access conflict.\n", dev->name);
else { else {
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
unsigned char *buf = skb->data; unsigned char *buf = (void *)(skb+1);
if (net_debug > 4) if (net_debug > 4)
printk("%s: Transmitting a packet of length %d.\n", dev->name, printk("%s: Transmitting a packet of length %d.\n", dev->name,
...@@ -551,14 +561,14 @@ net_rx(struct device *dev) ...@@ -551,14 +561,14 @@ net_rx(struct device *dev)
skb->len = pkt_len; skb->len = pkt_len;
skb->dev = dev; skb->dev = dev;
/* 'skb->data' points to the start of sk_buff data area. */ /* 'skb+1' points to the start of sk_buff data area. */
insw(ioaddr + DATAPORT, skb->data, (pkt_len + 1) >> 1); insw(ioaddr + DATAPORT, (void *)(skb+1), (pkt_len + 1) >> 1);
if (net_debug > 5) { if (net_debug > 5) {
int i; int i;
printk("%s: Rxed packet of length %d: ", dev->name, pkt_len); printk("%s: Rxed packet of length %d: ", dev->name, pkt_len);
for (i = 0; i < 14; i++) for (i = 0; i < 14; i++)
printk(" %02x", skb->data[i]); printk(" %02x", ((unsigned char*)(skb + 1))[i]);
printk(".\n"); printk(".\n");
} }
......
...@@ -477,7 +477,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev) ...@@ -477,7 +477,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev)
/* For ethernet, fill in the header. This should really be done by a /* For ethernet, fill in the header. This should really be done by a
higher level, rather than duplicated for each ethernet adaptor. */ higher level, rather than duplicated for each ethernet adaptor. */
if (!skb->arp && dev->rebuild_header(skb->data, dev)) { if (!skb->arp && dev->rebuild_header(skb+1, dev)) {
skb->dev = dev; skb->dev = dev;
arp_queue (skb); arp_queue (skb);
return 0; return 0;
...@@ -490,7 +490,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev) ...@@ -490,7 +490,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev)
printk("%s: Transmitter access conflict.\n", dev->name); printk("%s: Transmitter access conflict.\n", dev->name);
else { else {
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
unsigned char *buf = skb->data; unsigned char *buf = (void *)(skb+1);
int flags; int flags;
/* Disable interrupts by writing 0x00 to the Interrupt Mask Register. /* Disable interrupts by writing 0x00 to the Interrupt Mask Register.
...@@ -686,11 +686,11 @@ static void net_rx(struct device *dev) ...@@ -686,11 +686,11 @@ static void net_rx(struct device *dev)
skb->len = pkt_len; skb->len = pkt_len;
skb->dev = dev; skb->dev = dev;
/* 'skb->data' points to the start of sk_buff data area. */ /* 'skb+1' points to the start of sk_buff data area. */
read_block(ioaddr, pkt_len, skb->data, dev->if_port); read_block(ioaddr, pkt_len, (unsigned char *)(skb + 1), dev->if_port);
if (net_debug > 6) { if (net_debug > 6) {
unsigned char *data = skb->data; unsigned char *data = (unsigned char *)(skb + 1);
printk(" data %02x%02x%02x %02x%02x%02x %02x%02x%02x %02x%02x%02x %02x%02x..", printk(" data %02x%02x%02x %02x%02x%02x %02x%02x%02x %02x%02x%02x %02x%02x..",
data[0], data[1], data[2], data[3], data[4], data[5], data[0], data[1], data[2], data[3], data[4], data[5],
data[6], data[7], data[8], data[9], data[10], data[11], data[6], data[7], data[8], data[9], data[10], data[11],
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
*/ */
static char *version = static char *version =
"eexpress.c:v0.06 10/27/93 Donald Becker (becker@super.org)\n"; "eexpress.c:v0.07 1/19/94 Donald Becker (becker@super.org)\n";
#include <linux/config.h> #include <linux/config.h>
...@@ -154,7 +154,7 @@ struct net_local { ...@@ -154,7 +154,7 @@ struct net_local {
#define ASIC_RESET 0x40 #define ASIC_RESET 0x40
#define _586_RESET 0x80 #define _586_RESET 0x80
/* Offsets into the System Control Block structure. */ /* Offsets to elements of the System Control Block structure. */
#define SCB_STATUS 0xc008 #define SCB_STATUS 0xc008
#define SCB_CMD 0xc00A #define SCB_CMD 0xc00A
#define CUC_START 0x0100 #define CUC_START 0x0100
...@@ -175,8 +175,8 @@ struct net_local { ...@@ -175,8 +175,8 @@ struct net_local {
program space than initializing the individual tables, and I feel it's much program space than initializing the individual tables, and I feel it's much
cleaner. cleaner.
The databook is particularly useless for the first two structures, I had The databook is particularly useless for the first two structures; they are
to use the Crynwr driver as an example. completely undocumented. I had to use the Crynwr driver as an example.
The memory setup is as follows: The memory setup is as follows:
*/ */
...@@ -194,17 +194,18 @@ struct net_local { ...@@ -194,17 +194,18 @@ struct net_local {
#define TX_BUF_START 0x0100 #define TX_BUF_START 0x0100
#define NUM_TX_BUFS 4 #define NUM_TX_BUFS 4
#define TX_BUF_SIZE (1518+14+20+16) /* packet+header+TBD */ #define TX_BUF_SIZE 0x0680 /* packet+header+TBD+extra (1518+14+20+16) */
#define TX_BUF_END 0x2000
#define RX_BUF_START 0x2000 #define RX_BUF_START 0x2000
#define RX_BUF_SIZE (0x640) /* packet+header+RBD+extra */ #define RX_BUF_SIZE (0x640) /* packet+header+RBD+extra */
#define RX_BUF_END 0x8000 #define RX_BUF_END 0x4000
/* /*
That's it: only 86 bytes to set up the beast, including every extra That's it: only 86 bytes to set up the beast, including every extra
command available. The 170 byte buffer at DUMP_DATA is shared between the command available. The 170 byte buffer at DUMP_DATA is shared between the
Dump command (called only by the diagnostic program) and the SetMulticastList Dump command (called only by the diagnostic program) and the SetMulticastList
command. command.
To complete the memory setup you only have to write the station address at To complete the memory setup you only have to write the station address at
SA_OFFSET and create the Tx & Rx buffer lists. SA_OFFSET and create the Tx & Rx buffer lists.
...@@ -326,6 +327,7 @@ express_probe(struct device *dev) ...@@ -326,6 +327,7 @@ express_probe(struct device *dev)
#ifdef notdef #ifdef notdef
for (i = 16; i > 0; i--) for (i = 16; i > 0; i--)
sum += inb(id_addr); sum += inb(id_addr);
printk("EtherExpress ID checksum is %04x.\n", sum);
#else #else
for (i = 4; i > 0; i--) { for (i = 4; i > 0; i--) {
short id_val = inb(id_addr); short id_val = inb(id_addr);
...@@ -353,7 +355,7 @@ int eexp_probe1(struct device *dev, short ioaddr) ...@@ -353,7 +355,7 @@ int eexp_probe1(struct device *dev, short ioaddr)
station_addr[1] = read_eeprom(ioaddr, 3); station_addr[1] = read_eeprom(ioaddr, 3);
station_addr[2] = read_eeprom(ioaddr, 4); station_addr[2] = read_eeprom(ioaddr, 4);
/* Check the first three octets of the S.A. for the manufactor's code. */ /* Check the first three octets of the S.A. for the manufactor's code. */
if (station_addr[2] != 0x00aa || (station_addr[1] & 0xff00) != 0x0000) { if (station_addr[2] != 0x00aa || (station_addr[1] & 0xff00) != 0x0000) {
printk(" rejected (invalid address %04x%04x%04x).\n", printk(" rejected (invalid address %04x%04x%04x).\n",
station_addr[2], station_addr[1], station_addr[0]); station_addr[2], station_addr[1], station_addr[0]);
...@@ -511,7 +513,7 @@ eexp_send_packet(struct sk_buff *skb, struct device *dev) ...@@ -511,7 +513,7 @@ eexp_send_packet(struct sk_buff *skb, struct device *dev)
/* For ethernet, fill in the header. This should really be done by a /* For ethernet, fill in the header. This should really be done by a
higher level, rather than duplicated for each ethernet adaptor. */ higher level, rather than duplicated for each ethernet adaptor. */
if (!skb->arp && dev->rebuild_header(skb->data, dev)) { if (!skb->arp && dev->rebuild_header(skb+1, dev)) {
skb->dev = dev; skb->dev = dev;
arp_queue (skb); arp_queue (skb);
return 0; return 0;
...@@ -523,7 +525,7 @@ eexp_send_packet(struct sk_buff *skb, struct device *dev) ...@@ -523,7 +525,7 @@ eexp_send_packet(struct sk_buff *skb, struct device *dev)
printk("%s: Transmitter access conflict.\n", dev->name); printk("%s: Transmitter access conflict.\n", dev->name);
else { else {
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
unsigned char *buf = skb->data; unsigned char *buf = (void *)(skb+1);
/* Disable the 82586's input to the interrupt line. */ /* Disable the 82586's input to the interrupt line. */
outb(irqrmap[dev->irq], ioaddr + SET_IRQ); outb(irqrmap[dev->irq], ioaddr + SET_IRQ);
...@@ -551,8 +553,8 @@ eexp_interrupt(int reg_ptr) ...@@ -551,8 +553,8 @@ eexp_interrupt(int reg_ptr)
struct device *dev = (struct device *)(irq2dev_map[irq]); struct device *dev = (struct device *)(irq2dev_map[irq]);
struct net_local *lp; struct net_local *lp;
int ioaddr, status, boguscount = 0; int ioaddr, status, boguscount = 0;
short ack_cmd = 0; short ack_cmd;
if (dev == NULL) { if (dev == NULL) {
printk ("net_interrupt(): irq %d for unknown device.\n", irq); printk ("net_interrupt(): irq %d for unknown device.\n", irq);
return; return;
...@@ -595,7 +597,7 @@ eexp_interrupt(int reg_ptr) ...@@ -595,7 +597,7 @@ eexp_interrupt(int reg_ptr)
if (net_debug > 5) if (net_debug > 5)
printk("Reaped %x, Tx status %04x.\n" , lp->tx_reap, tx_status); printk("Reaped %x, Tx status %04x.\n" , lp->tx_reap, tx_status);
lp->tx_reap += TX_BUF_SIZE; lp->tx_reap += TX_BUF_SIZE;
if (lp->tx_reap > RX_BUF_START - TX_BUF_SIZE) if (lp->tx_reap > TX_BUF_END - TX_BUF_SIZE)
lp->tx_reap = TX_BUF_START; lp->tx_reap = TX_BUF_START;
if (++boguscount > 4) if (++boguscount > 4)
break; break;
...@@ -611,22 +613,43 @@ eexp_interrupt(int reg_ptr) ...@@ -611,22 +613,43 @@ eexp_interrupt(int reg_ptr)
ack_cmd = status & 0xf000; ack_cmd = status & 0xf000;
if ((status & 0x0700) != 0x0200 && dev->start) { if ((status & 0x0700) != 0x0200 && dev->start) {
if (net_debug) short saved_write_ptr = inw(ioaddr + WRITE_PTR);
if (net_debug > 1)
printk("%s: Command unit stopped, status %04x, restarting.\n", printk("%s: Command unit stopped, status %04x, restarting.\n",
dev->name, status); dev->name, status);
/* If this ever occurs we should really re-write the idle loop, reset /* If this ever occurs we must re-write the idle loop, reset
the Tx list, and do a complete restart of the command unit. the Tx list, and do a complete restart of the command unit. */
For now we rely on the Tx timeout if the resume doesn't work. */ outw(IDLELOOP, ioaddr + WRITE_PTR);
ack_cmd |= CUC_RESUME; outw(0, ioaddr);
outw(CmdNOp, ioaddr);
outw(IDLELOOP, ioaddr);
outw(IDLELOOP, SCB_CBL);
lp->tx_cmd_link = IDLELOOP + 4;
lp->tx_head = lp->tx_reap = TX_BUF_START;
/* Restore the saved write pointer. */
outw(saved_write_ptr, ioaddr + WRITE_PTR);
ack_cmd |= CUC_START;
} }
if ((status & 0x0070) != 0x0040 && dev->start) { if ((status & 0x0070) != 0x0040 && dev->start) {
short saved_write_ptr = inw(ioaddr + WRITE_PTR); short saved_write_ptr = inw(ioaddr + WRITE_PTR);
/* The Rx unit is not ready, it must be hung. Restart the receiver by /* The Rx unit is not ready, it must be hung. Restart the receiver by
initializing the rx buffers, and issuing an Rx start command. */ initializing the rx buffers, and issuing an Rx start command. */
if (net_debug) lp->stats.rx_errors++;
printk("%s: Rx unit stopped, status %04x, restarting.\n", if (net_debug > 1) {
dev->name, status); int cur_rxbuf = RX_BUF_START;
printk("%s: Rx unit stopped status %04x rx head %04x tail %04x.\n",
dev->name, status, lp->rx_head, lp->rx_tail);
while (cur_rxbuf <= RX_BUF_END - RX_BUF_SIZE) {
int i;
printk(" Rx buf at %04x:", cur_rxbuf);
outw(cur_rxbuf, ioaddr + READ_PTR);
for (i = 0; i < 0x20; i += 2)
printk(" %04x", inw(ioaddr));
printk(".\n");
cur_rxbuf += RX_BUF_SIZE;
}
}
init_rx_bufs(dev); init_rx_bufs(dev);
outw(RX_BUF_START, SCB_RFA); outw(RX_BUF_START, SCB_RFA);
outw(saved_write_ptr, ioaddr + WRITE_PTR); outw(saved_write_ptr, ioaddr + WRITE_PTR);
...@@ -813,8 +836,7 @@ init_82586_mem(struct device *dev) ...@@ -813,8 +836,7 @@ init_82586_mem(struct device *dev)
} }
/* Initialize the Rx-block list. */ /* Initialize the Rx-block list. */
static void static void init_rx_bufs(struct device *dev)
init_rx_bufs(struct device *dev)
{ {
struct net_local *lp = (struct net_local *)dev->priv; struct net_local *lp = (struct net_local *)dev->priv;
short ioaddr = dev->base_addr; short ioaddr = dev->base_addr;
...@@ -828,14 +850,14 @@ init_rx_bufs(struct device *dev) ...@@ -828,14 +850,14 @@ init_rx_bufs(struct device *dev)
outw(0x0000, ioaddr); /* Command */ outw(0x0000, ioaddr); /* Command */
outw(cur_rxbuf + RX_BUF_SIZE, ioaddr); /* Link */ outw(cur_rxbuf + RX_BUF_SIZE, ioaddr); /* Link */
outw(cur_rxbuf + 22, ioaddr); /* Buffer offset */ outw(cur_rxbuf + 22, ioaddr); /* Buffer offset */
outw(0x0000, ioaddr); /* Pad for dest addr. */ outw(0xFeed, ioaddr); /* Pad for dest addr. */
outw(0x0000, ioaddr); outw(0xF00d, ioaddr);
outw(0x0000, ioaddr); outw(0xF001, ioaddr);
outw(0x0000, ioaddr); /* Pad for source addr. */ outw(0x0505, ioaddr); /* Pad for source addr. */
outw(0x0000, ioaddr); outw(0x2424, ioaddr);
outw(0x0000, ioaddr); outw(0x6565, ioaddr);
outw(0x0000, ioaddr); /* Pad for protocol. */ outw(0xdeaf, ioaddr); /* Pad for protocol. */
outw(0x0000, ioaddr); /* Buffer: Actual count */ outw(0x0000, ioaddr); /* Buffer: Actual count */
outw(-1, ioaddr); /* Buffer: Next (none). */ outw(-1, ioaddr); /* Buffer: Next (none). */
outw(cur_rxbuf + 0x20, ioaddr); /* Buffer: Address low */ outw(cur_rxbuf + 0x20, ioaddr); /* Buffer: Address low */
...@@ -890,7 +912,7 @@ hardware_send_packet(struct device *dev, void *buf, short length) ...@@ -890,7 +912,7 @@ hardware_send_packet(struct device *dev, void *buf, short length)
/* Set the next free tx region. */ /* Set the next free tx region. */
lp->tx_head = tx_block + TX_BUF_SIZE; lp->tx_head = tx_block + TX_BUF_SIZE;
if (lp->tx_head > RX_BUF_START - TX_BUF_SIZE) if (lp->tx_head > TX_BUF_END - TX_BUF_SIZE)
lp->tx_head = TX_BUF_START; lp->tx_head = TX_BUF_START;
if (net_debug > 4) { if (net_debug > 4) {
...@@ -960,7 +982,7 @@ eexp_rx(struct device *dev) ...@@ -960,7 +982,7 @@ eexp_rx(struct device *dev)
outw(data_buffer_addr + 10, ioaddr + READ_PTR); outw(data_buffer_addr + 10, ioaddr + READ_PTR);
insw(ioaddr, skb->data, (pkt_len + 1) >> 1); insw(ioaddr, (void *)(skb+1), (pkt_len + 1) >> 1);
#ifdef HAVE_NETIF_RX #ifdef HAVE_NETIF_RX
netif_rx(skb); netif_rx(skb);
...@@ -985,7 +1007,7 @@ eexp_rx(struct device *dev) ...@@ -985,7 +1007,7 @@ eexp_rx(struct device *dev)
printk("%s: Rx next frame at %#x is %#x instead of %#x.\n", dev->name, printk("%s: Rx next frame at %#x is %#x instead of %#x.\n", dev->name,
rx_head, next_rx_frame, rx_head + RX_BUF_SIZE); rx_head, next_rx_frame, rx_head + RX_BUF_SIZE);
next_rx_frame = rx_head + RX_BUF_SIZE; next_rx_frame = rx_head + RX_BUF_SIZE;
if (next_rx_frame >= RX_BUF_END - RX_BUF_SIZE) if (next_rx_frame >= RX_BUF_END - RX_BUF_SIZE)
next_rx_frame = RX_BUF_START; next_rx_frame = RX_BUF_START;
} }
#endif #endif
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
*/ */
static char *version = static char *version =
"hp.c:v0.99.14a 12/2/93 Donald Becker (becker@super.org)\n"; "hp.c:v0.99.15c 2/11/94 Donald Becker (becker@super.org)\n";
#include <linux/config.h> #include <linux/config.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -56,7 +56,7 @@ static void hp_block_output(struct device *dev, int count, ...@@ -56,7 +56,7 @@ static void hp_block_output(struct device *dev, int count,
static void hp_init_card(struct device *dev); static void hp_init_card(struct device *dev);
/* The map from IRQ number to HP_CONFIGURE register setting. */ /* The map from IRQ number to HP_CONFIGURE register setting. */
/* My default is IRQ5 0 1 2 3 4 5 6 7 8 9 10 11 */ /* My default is IRQ5 0 1 2 3 4 5 6 7 8 9 10 11 */
static char irqmap[16] = { 0, 0, 4, 6, 8,10, 0,14, 0, 4, 2,12,0,0,0,0}; static char irqmap[16] = { 0, 0, 4, 6, 8,10, 0,14, 0, 4, 2,12,0,0,0,0};
...@@ -86,22 +86,17 @@ int hp_probe(struct device *dev) ...@@ -86,22 +86,17 @@ int hp_probe(struct device *dev)
int hpprobe1(struct device *dev, int ioaddr) int hpprobe1(struct device *dev, int ioaddr)
{ {
int status, i, board_id, wordmode; int i, board_id, wordmode;
char *name; char *name;
unsigned char *station_addr = dev->dev_addr; unsigned char *station_addr = dev->dev_addr;
/* Check for the HP physical address, 08 00 09 xx xx xx. */ /* Check for the HP physical address, 08 00 09 xx xx xx. */
/* This really isn't good enough: we may pick up HP LANCE boards
also! Avoid the lance 0x5757 signature. */
if (inb(ioaddr) != 0x08 if (inb(ioaddr) != 0x08
|| inb(ioaddr+1) != 0x00 || inb(ioaddr+1) != 0x00
|| inb(ioaddr+2) != 0x09) || inb(ioaddr+2) != 0x09
return ENODEV; || inb(ioaddr+14) == 0x57)
/* This really isn't good enough, we may pick up HP LANCE boards also! */
/* Verify that there is a 8390 at the expected location. */
outb(E8390_NODMA + E8390_STOP, ioaddr);
SLOW_DOWN_IO;
status = inb(ioaddr);
if (status != 0x21 && status != 0x23)
return ENODEV; return ENODEV;
/* Set up the parameters based on the board ID. /* Set up the parameters based on the board ID.
...@@ -320,9 +315,10 @@ hp_init_card(struct device *dev) ...@@ -320,9 +315,10 @@ hp_init_card(struct device *dev)
/* /*
* Local variables: * Local variables:
* compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c hp.c" * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c hp.c"
* version-control: t * version-control: t
* kept-new-versions: 5 * kept-new-versions: 5
* tab-width: 4 * tab-width: 4
* c-indent-level: 4
* End: * End:
*/ */
...@@ -205,7 +205,7 @@ struct lance_private { ...@@ -205,7 +205,7 @@ struct lance_private {
int pad0, pad1; /* Used for alignment */ int pad0, pad1; /* Used for alignment */
}; };
static unsigned long lance_probe1(short ioaddr, unsigned long mem_start); unsigned long lance_probe1(short ioaddr, unsigned long mem_start);
static int lance_open(struct device *dev); static int lance_open(struct device *dev);
static void lance_init_ring(struct device *dev); static void lance_init_ring(struct device *dev);
static int lance_start_xmit(struct sk_buff *skb, struct device *dev); static int lance_start_xmit(struct sk_buff *skb, struct device *dev);
...@@ -236,7 +236,7 @@ unsigned long lance_init(unsigned long mem_start, unsigned long mem_end) ...@@ -236,7 +236,7 @@ unsigned long lance_init(unsigned long mem_start, unsigned long mem_end)
return mem_start; return mem_start;
} }
static unsigned long lance_probe1(short ioaddr, unsigned long mem_start) unsigned long lance_probe1(short ioaddr, unsigned long mem_start)
{ {
struct device *dev; struct device *dev;
struct lance_private *lp; struct lance_private *lp;
...@@ -512,7 +512,7 @@ lance_start_xmit(struct sk_buff *skb, struct device *dev) ...@@ -512,7 +512,7 @@ lance_start_xmit(struct sk_buff *skb, struct device *dev)
} }
/* Fill in the ethernet header. */ /* Fill in the ethernet header. */
if (!skb->arp && dev->rebuild_header(skb->data, dev)) { if (!skb->arp && dev->rebuild_header(skb+1, dev)) {
skb->dev = dev; skb->dev = dev;
arp_queue (skb); arp_queue (skb);
return 0; return 0;
...@@ -553,11 +553,11 @@ lance_start_xmit(struct sk_buff *skb, struct device *dev) ...@@ -553,11 +553,11 @@ lance_start_xmit(struct sk_buff *skb, struct device *dev)
/* If any part of this buffer is >16M we must copy it to a low-memory /* If any part of this buffer is >16M we must copy it to a low-memory
buffer. */ buffer. */
if ((int)(skb->data) + skb->len > 0x01000000) { if ((int)(skb+1) + skb->len > 0x01000000) {
if (lance_debug > 5) if (lance_debug > 5)
printk("%s: bouncing a high-memory packet (%#x).\n", printk("%s: bouncing a high-memory packet (%#x).\n",
dev->name, (int)skb->data); dev->name, (int)(skb+1));
memcpy(&lp->tx_bounce_buffs[entry], skb->data, skb->len); memcpy(&lp->tx_bounce_buffs[entry], skb+1, skb->len);
lp->tx_ring[entry].base = lp->tx_ring[entry].base =
(int)(lp->tx_bounce_buffs + entry) | 0x83000000; (int)(lp->tx_bounce_buffs + entry) | 0x83000000;
if (skb->free) if (skb->free)
...@@ -567,7 +567,7 @@ lance_start_xmit(struct sk_buff *skb, struct device *dev) ...@@ -567,7 +567,7 @@ lance_start_xmit(struct sk_buff *skb, struct device *dev)
/* Gimme!!! */ /* Gimme!!! */
if(skb->free==0) if(skb->free==0)
skb_kept_by_device(skb); skb_kept_by_device(skb);
lp->tx_ring[entry].base = (int)skb->data | 0x83000000; lp->tx_ring[entry].base = (int)(skb+1) | 0x83000000;
} }
lp->cur_tx++; lp->cur_tx++;
...@@ -638,11 +638,12 @@ lance_interrupt(int reg_ptr) ...@@ -638,11 +638,12 @@ lance_interrupt(int reg_ptr)
if (err_status & 0x0800) lp->stats.tx_carrier_errors++; if (err_status & 0x0800) lp->stats.tx_carrier_errors++;
if (err_status & 0x1000) lp->stats.tx_window_errors++; if (err_status & 0x1000) lp->stats.tx_window_errors++;
if (err_status & 0x4000) lp->stats.tx_fifo_errors++; if (err_status & 0x4000) lp->stats.tx_fifo_errors++;
/* We should re-init() after the FIFO error. */ /* Perhaps we should re-init() after the FIFO error. */
} else if (status & 0x18000000) } else {
lp->stats.collisions++; if (status & 0x18000000)
else lp->stats.collisions++;
lp->stats.tx_packets++; lp->stats.tx_packets++;
}
/* We don't free the skb if it's a data-only copy in the bounce /* We don't free the skb if it's a data-only copy in the bounce
buffer. The address checks here are sorted -- the first test buffer. The address checks here are sorted -- the first test
...@@ -726,7 +727,7 @@ lance_rx(struct device *dev) ...@@ -726,7 +727,7 @@ lance_rx(struct device *dev)
skb->mem_addr = skb; skb->mem_addr = skb;
skb->len = pkt_len; skb->len = pkt_len;
skb->dev = dev; skb->dev = dev;
memcpy(skb->data, memcpy((unsigned char *) (skb + 1),
(unsigned char *)(lp->rx_ring[entry].base & 0x00ffffff), (unsigned char *)(lp->rx_ring[entry].base & 0x00ffffff),
pkt_len); pkt_len);
#ifdef HAVE_NETIF_RX #ifdef HAVE_NETIF_RX
...@@ -836,6 +837,12 @@ set_multicast_list(struct device *dev, int num_addrs, void *addrs) ...@@ -836,6 +837,12 @@ set_multicast_list(struct device *dev, int num_addrs, void *addrs)
outw(0x0142, ioaddr+LANCE_DATA); /* Resume normal operation. */ outw(0x0142, ioaddr+LANCE_DATA); /* Resume normal operation. */
} }
#endif #endif
#ifdef HAVE_DEVLIST
static unsigned int lance_portlist[] = {0x300, 0x320, 0x340, 0x360, 0};
struct netdev_entry lance_drv =
{"lance", lance_probe1, LANCE_TOTAL_SIZE, lance_portlist};
#endif
/* /*
* Local variables: * Local variables:
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
/* Routines for the NatSemi-based designs (NE[12]000). */ /* Routines for the NatSemi-based designs (NE[12]000). */
static char *version = static char *version =
"ne.c:v0.99-14a 12/3/93 Donald Becker (becker@super.org)\n"; "ne.c:v0.99-15b 2/8/94 Donald Becker (becker@super.org)\n";
#include <linux/config.h> #include <linux/config.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -155,11 +155,11 @@ static int neprobe1(int ioaddr, struct device *dev, int verbose) ...@@ -155,11 +155,11 @@ static int neprobe1(int ioaddr, struct device *dev, int verbose)
} }
if (wordlength == 2) { if (wordlength == 2) {
/* We must set the 8390 for word mode, AND RESET IT. */ /* We must set the 8390 for word mode. */
int tmp; int tmp;
outb_p(0x49, ioaddr + EN0_DCFG); outb_p(0x49, ioaddr + EN0_DCFG);
tmp = inb_p(NE_BASE + NE_RESET); /* We used to reset the ethercard here, but it doesn't seem
outb(tmp, NE_BASE + NE_RESET); to be necessary. */
/* Un-double the SA_prom values. */ /* Un-double the SA_prom values. */
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)
SA_prom[i] = SA_prom[i+i]; SA_prom[i] = SA_prom[i+i];
......
...@@ -523,7 +523,6 @@ sl_xmit(struct sk_buff *skb, struct device *dev) ...@@ -523,7 +523,6 @@ sl_xmit(struct sk_buff *skb, struct device *dev)
{ {
struct tty_struct *tty; struct tty_struct *tty;
struct slip *sl; struct slip *sl;
int size; int size;
/* Find the correct SLIP channel to use. */ /* Find the correct SLIP channel to use. */
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
*/ */
static char *version = static char *version =
"smc-ultra.c:v0.05 12/21/93 Donald Becker (becker@super.org)\n"; "smc-ultra.c:v0.06 2/9/94 Donald Becker (becker@super.org)\n";
#include <linux/config.h> #include <linux/config.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -139,7 +139,7 @@ int ultraprobe1(int ioaddr, struct device *dev) ...@@ -139,7 +139,7 @@ int ultraprobe1(int ioaddr, struct device *dev)
dev->base_addr = ioaddr+ULTRA_NIC_OFFSET; dev->base_addr = ioaddr+ULTRA_NIC_OFFSET;
{ {
int addr_tbl[4] = {0x0C0000, 0x0D0000, 0xFC0000, 0xFD0000}; int addr_tbl[4] = {0x0C0000, 0x0E0000, 0xFC0000, 0xFE0000};
short num_pages_tbl[4] = {0x20, 0x40, 0x80, 0xff}; short num_pages_tbl[4] = {0x20, 0x40, 0x80, 0xff};
dev->mem_start = ((addr & 0x0f) << 13) + addr_tbl[(addr >> 6) & 3] ; dev->mem_start = ((addr & 0x0f) << 13) + addr_tbl[(addr >> 6) & 3] ;
......
This diff is collapsed.
...@@ -954,7 +954,9 @@ int shrink_buffers(unsigned int priority) ...@@ -954,7 +954,9 @@ int shrink_buffers(unsigned int priority)
bh = free_list; bh = free_list;
i = nr_buffers >> priority; i = nr_buffers >> priority;
for ( ; i-- > 0 ; bh = bh->b_next_free) { for ( ; i-- > 0 ; bh = bh->b_next_free) {
if (bh->b_count) { if (bh->b_count ||
(priority >= 5 &&
mem_map[MAP_NR((unsigned long) bh->b_data)] > 1)) {
put_last_free(bh); put_last_free(bh);
continue; continue;
} }
......
...@@ -45,7 +45,7 @@ static int read_core(struct inode * inode, struct file * file,char * buf, int co ...@@ -45,7 +45,7 @@ static int read_core(struct inode * inode, struct file * file,char * buf, int co
if (p >= high_memory + PAGE_SIZE) if (p >= high_memory + PAGE_SIZE)
return 0; return 0;
if (count > high_memory + PAGE_SIZE - p) if (count > high_memory + PAGE_SIZE - p)
count = high_memory - p; count = high_memory + PAGE_SIZE - p;
read = 0; read = 0;
if (p < sizeof(struct user) && count > 0) { if (p < sizeof(struct user) && count > 0) {
......
...@@ -5,9 +5,10 @@ ...@@ -5,9 +5,10 @@
* *
* Global definitions for the Ethernet IEE 802.3 interface. * Global definitions for the Ethernet IEE 802.3 interface.
* *
* Version: @(#)if_ether.h 1.0.1 03/15/93 * Version: @(#)if_ether.h 1.0.1a 02/08/94
* *
* Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Donald Becker, <becker@super.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
...@@ -18,12 +19,14 @@ ...@@ -18,12 +19,14 @@
#define _LINUX_IF_ETHER_H #define _LINUX_IF_ETHER_H
/* IEEE 802.3 Ethernet magic constants. */ /* IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble
#define ETH_ALEN 6 /* #bytes in eth addr */ and FCS/CRC (frame check sequence). */
#define ETH_HLEN 14 /* #bytes in eth header */ #define ETH_ALEN 6 /* Octets in one ethernet addr */
#define ETH_ZLEN 60 /* min #bytes in frame */ #define ETH_HLEN 14 /* Total octets in header. */
#define ETH_FLEN 1536 /* max #bytes in frame */ #define ETH_ZLEN 60 /* Min. octets in frame sans FCS */
#define ETH_DLEN (ETH_FLEN - ETH_HLEN) /* max #bytes of data */ #define ETH_DATA_LEN 1500 /* Max. octets in payload */
#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */
/* These are the defined Ethernet Protocol ID's. */ /* These are the defined Ethernet Protocol ID's. */
#define ETH_P_LOOP 0x0060 /* Ethernet Loopback packet */ #define ETH_P_LOOP 0x0060 /* Ethernet Loopback packet */
...@@ -38,9 +41,6 @@ ...@@ -38,9 +41,6 @@
#define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */ #define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */
#define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */ #define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */
/* Define the Ethernet Broadcast Address (48 bits set to "1"). */
#define ETH_A_BCAST "\377\377\377\377\377\377"
/* This is an Ethernet frame header. */ /* This is an Ethernet frame header. */
struct ethhdr { struct ethhdr {
unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
...@@ -48,21 +48,6 @@ struct ethhdr { ...@@ -48,21 +48,6 @@ struct ethhdr {
unsigned short h_proto; /* packet type ID field */ unsigned short h_proto; /* packet type ID field */
}; };
/* This is the complete Ethernet frame. */
struct ethframe {
struct ethhdr f_hdr; /* frame header */
char f_data[ETH_DLEN]; /* frame data (variable)*/
};
/* Receiver modes */
#define ETH_MODE_MONITOR 1 /* Monitor mode - no receive */
#define ETH_MODE_PHYS 2 /* Physical address receive only */
#define ETH_MODE_BCAST 3 /* Broadcast receive + mode 2 */
#define ETH_MODE_MCAST 4 /* Multicast receive + mode 3 */
#define ETH_MODE_PROMISC 5 /* Promiscuous mode - receive all */
/* Ethernet statistics collection data. */ /* Ethernet statistics collection data. */
struct enet_statistics{ struct enet_statistics{
int rx_packets; /* total packets received */ int rx_packets; /* total packets received */
......
...@@ -399,7 +399,7 @@ extern long tty_init(long); ...@@ -399,7 +399,7 @@ extern long tty_init(long);
extern void flush_input(struct tty_struct * tty); extern void flush_input(struct tty_struct * tty);
extern void flush_output(struct tty_struct * tty); extern void flush_output(struct tty_struct * tty);
extern void wait_until_sent(struct tty_struct * tty); extern void wait_until_sent(struct tty_struct * tty, int timeout);
extern int check_change(struct tty_struct * tty, int channel); extern int check_change(struct tty_struct * tty, int channel);
extern void stop_tty(struct tty_struct * tty); extern void stop_tty(struct tty_struct * tty);
extern void start_tty(struct tty_struct * tty); extern void start_tty(struct tty_struct * tty);
......
...@@ -45,24 +45,19 @@ void ipc_init (void) ...@@ -45,24 +45,19 @@ void ipc_init (void)
* to ipc resources. return 0 if allowed * to ipc resources. return 0 if allowed
*/ */
int ipcperms (struct ipc_perm *ipcp, short flag) int ipcperms (struct ipc_perm *ipcp, short flag)
{ { /* flag will most probably be 0 or S_...UGO from <linux/stat.h> */
int i; mode_t perm; uid_t euid; int egid; int requested_mode, granted_mode;
if (suser()) if (suser())
return 0; return 0;
requested_mode = (flag >> 6) | (flag >> 3) | flag;
perm = S_IRWXO; euid = current->euid; granted_mode = ipcp->mode;
if (current->euid == ipcp->cuid || current->euid == ipcp->uid)
if (euid == ipcp->cuid || euid == ipcp->uid) granted_mode >>= 6;
perm = S_IRWXU; else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid))
else { granted_mode >>= 3;
for (i = 0; (egid = current->groups[i]) != NOGROUP; i++) /* is there some bit set in requested_mode but not in granted_mode? */
if ((egid == ipcp->cgid) || (egid == ipcp->gid)) { if (requested_mode & ~granted_mode & 0007)
perm = S_IRWXG;
break;
}
}
if (!(flag & perm) || flag & perm & ~ipcp->mode)
return -1; return -1;
return 0; return 0;
} }
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
# #
# #
trap "rm -f ksyms.tmp ksyms.lst" 1 2 trap "rm -f ksyms.tmp ksyms.lst ; exit 1" 1 2
sed -e '/^#/d' -e '/^[ ]*$/d' ksyms.lst | sort > ksyms.tmp sed -e '/^#/d' -e '/^[ ]*$/d' ksyms.lst | sort > ksyms.tmp
......
...@@ -89,8 +89,8 @@ asmlinkage void alignment_check(void); ...@@ -89,8 +89,8 @@ asmlinkage void alignment_check(void);
printk("EIP: %04x:%08lx\nEFLAGS: %08lx\n", 0xffff & regs->cs,regs->eip,regs->eflags); printk("EIP: %04x:%08lx\nEFLAGS: %08lx\n", 0xffff & regs->cs,regs->eip,regs->eflags);
printk("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n", printk("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n",
regs->eax, regs->ebx, regs->ecx, regs->edx); regs->eax, regs->ebx, regs->ecx, regs->edx);
printk("esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n", printk("esi: %08lx edi: %08lx ebp: %08lx\n",
regs->esi, regs->edi, regs->ebp, regs->esp); regs->esi, regs->edi, regs->ebp);
printk("ds: %04x es: %04x fs: %04x gs: %04x\n", printk("ds: %04x es: %04x fs: %04x gs: %04x\n",
regs->ds, regs->es, regs->fs, regs->gs); regs->ds, regs->es, regs->fs, regs->gs);
store_TR(i); store_TR(i);
...@@ -98,11 +98,6 @@ asmlinkage void alignment_check(void); ...@@ -98,11 +98,6 @@ asmlinkage void alignment_check(void);
for(i=0;i<20;i++) for(i=0;i<20;i++)
printk("%02x ",0xff & get_seg_byte(regs->cs,(i+(char *)regs->eip))); printk("%02x ",0xff & get_seg_byte(regs->cs,(i+(char *)regs->eip)));
printk("\n"); printk("\n");
#if 0
for(i=0;i<5;i++)
printk("%08lx ", get_seg_long(regs->ss,(i+(unsigned long *)regs->esp)));
printk("\n");
#endif
do_exit(SIGSEGV); do_exit(SIGSEGV);
} }
......
...@@ -34,6 +34,12 @@ ...@@ -34,6 +34,12 @@
* Alan Cox : Save IP header pointer for later * Alan Cox : Save IP header pointer for later
* Alan Cox : ip option setting * Alan Cox : ip option setting
* Alan Cox : Use ip_tos/ip_ttl settings * Alan Cox : Use ip_tos/ip_ttl settings
* Alan Cox : Fragmentation bogosity removed
* (Thanks to Mark.Bush@prg.ox.ac.uk)
* Dmitry Gordchanin : Send of a raw packet crash fix.
* Alan Cox : Silly ip bug when an overlength
* fragment turns up. Now frees the
* queue.
* *
* To Fix: * To Fix:
* IP option processing is mostly not needed. ip_forward needs to know about routing rules * IP option processing is mostly not needed. ip_forward needs to know about routing rules
...@@ -785,6 +791,7 @@ static struct sk_buff *ip_glue(struct ipq *qp) ...@@ -785,6 +791,7 @@ static struct sk_buff *ip_glue(struct ipq *qp)
if(count+fp->len>skb->len) if(count+fp->len>skb->len)
{ {
printk("Invalid fragment list: Fragment over size.\n"); printk("Invalid fragment list: Fragment over size.\n");
ip_free(qp);
kfree_skb(skb,FREE_WRITE); kfree_skb(skb,FREE_WRITE);
return NULL; return NULL;
} }
...@@ -970,7 +977,9 @@ static struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct ...@@ -970,7 +977,9 @@ static struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct
/* Point into the IP datagram header. */ /* Point into the IP datagram header. */
raw = skb->data; raw = skb->data;
iph = (struct iphdr *) (raw + dev->hard_header_len); iph = (struct iphdr *) (raw + dev->hard_header_len);
skb->ip_hdr = iph;
/* Setup starting values. */ /* Setup starting values. */
hlen = (iph->ihl * sizeof(unsigned long)); hlen = (iph->ihl * sizeof(unsigned long));
left = ntohs(iph->tot_len) - hlen; left = ntohs(iph->tot_len) - hlen;
...@@ -1008,6 +1017,7 @@ static struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct ...@@ -1008,6 +1017,7 @@ static struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct
while(left > 0) while(left > 0)
{ {
len = left; len = left;
#ifdef OLD
if (len+8 > mtu) if (len+8 > mtu)
len = (dev->mtu - hlen - 8); len = (dev->mtu - hlen - 8);
if ((left - len) >= 8) if ((left - len) >= 8)
...@@ -1015,6 +1025,18 @@ static struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct ...@@ -1015,6 +1025,18 @@ static struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct
len /= 8; len /= 8;
len *= 8; len *= 8;
} }
#else
/* IF: it doesn't fit, use 'mtu' - the data space left */
if (len > mtu)
len = mtu;
/* IF: we are not sending upto and including the packet end
then align the next start on an eight byte boundary */
if (len < left)
{
len/=8;
len*=8;
}
#endif
DPRINTF((DBG_IP,"IP: frag: creating fragment of %d bytes (%d total)\n", DPRINTF((DBG_IP,"IP: frag: creating fragment of %d bytes (%d total)\n",
len, len + hlen)); len, len + hlen));
...@@ -1368,6 +1390,7 @@ ip_queue_xmit(struct sock *sk, struct device *dev, ...@@ -1368,6 +1390,7 @@ ip_queue_xmit(struct sock *sk, struct device *dev,
ptr = skb->data; ptr = skb->data;
ptr += dev->hard_header_len; ptr += dev->hard_header_len;
iph = (struct iphdr *)ptr; iph = (struct iphdr *)ptr;
skb->ip_hdr = iph;
iph->tot_len = ntohs(skb->len-dev->hard_header_len); iph->tot_len = ntohs(skb->len-dev->hard_header_len);
if(skb->len > dev->mtu) if(skb->len > dev->mtu)
......
...@@ -72,8 +72,7 @@ struct sk_buff { ...@@ -72,8 +72,7 @@ struct sk_buff {
volatile char acked, volatile char acked,
used, used,
free, free,
arp, arp;
urg_used;
unsigned char tries,lock; /* Lock is now unused */ unsigned char tries,lock; /* Lock is now unused */
unsigned short users; /* User count - see datagram.c (and soon seqpacket.c/stream.c) */ unsigned short users; /* User count - see datagram.c (and soon seqpacket.c/stream.c) */
unsigned long padding[0]; unsigned long padding[0];
......
...@@ -130,7 +130,7 @@ print_sk(struct sock *sk) ...@@ -130,7 +130,7 @@ print_sk(struct sock *sk)
printk(" retransmits = %ld, timeout = %d\n", sk->retransmits, sk->timeout); printk(" retransmits = %ld, timeout = %d\n", sk->retransmits, sk->timeout);
printk(" cong_window = %d, packets_out = %d\n", sk->cong_window, printk(" cong_window = %d, packets_out = %d\n", sk->cong_window,
sk->packets_out); sk->packets_out);
printk(" urg = %d shutdown=%d\n", sk->urg, sk->shutdown); printk(" shutdown=%d\n", sk->shutdown);
} }
...@@ -842,6 +842,8 @@ inet_create(struct socket *sock, int protocol) ...@@ -842,6 +842,8 @@ inet_create(struct socket *sock, int protocol)
sk->acked_seq = 0; sk->acked_seq = 0;
sk->copied_seq = 0; sk->copied_seq = 0;
sk->fin_seq = 0; sk->fin_seq = 0;
sk->urg_seq = 0;
sk->urg_data = 0;
sk->proc = 0; sk->proc = 0;
sk->rtt = TCP_WRITE_TIME << 3; sk->rtt = TCP_WRITE_TIME << 3;
sk->rto = TCP_WRITE_TIME; sk->rto = TCP_WRITE_TIME;
...@@ -859,7 +861,6 @@ inet_create(struct socket *sock, int protocol) ...@@ -859,7 +861,6 @@ inet_create(struct socket *sock, int protocol)
sk->priority = 1; sk->priority = 1;
sk->shutdown = 0; sk->shutdown = 0;
sk->urg = 0;
sk->keepopen = 0; sk->keepopen = 0;
sk->zapped = 0; sk->zapped = 0;
sk->done = 0; sk->done = 0;
......
...@@ -61,6 +61,8 @@ struct sock { ...@@ -61,6 +61,8 @@ struct sock {
unsigned long rcv_ack_seq; unsigned long rcv_ack_seq;
unsigned long window_seq; unsigned long window_seq;
unsigned long fin_seq; unsigned long fin_seq;
unsigned long urg_seq;
unsigned long urg_data;
/* /*
* Not all are volatile, but some are, so we * Not all are volatile, but some are, so we
...@@ -112,7 +114,6 @@ struct sock { ...@@ -112,7 +114,6 @@ struct sock {
volatile unsigned short cong_count; volatile unsigned short cong_count;
volatile unsigned short ssthresh; volatile unsigned short ssthresh;
volatile unsigned short packets_out; volatile unsigned short packets_out;
volatile unsigned short urg;
volatile unsigned short shutdown; volatile unsigned short shutdown;
volatile unsigned long rtt; volatile unsigned long rtt;
volatile unsigned long mdev; volatile unsigned long mdev;
......
This diff is collapsed.
...@@ -30,6 +30,9 @@ ...@@ -30,6 +30,9 @@
#define MIN_WRITE_SPACE 2048 #define MIN_WRITE_SPACE 2048
#define TCP_WINDOW_DIFF 2048 #define TCP_WINDOW_DIFF 2048
/* marks the urg_data as read */
#define URG_READ 0xdeadbeef
#define TCP_RETR1 7 /* #define TCP_RETR1 7 /*
* This is howmany retries it does before it * This is howmany retries it does before it
* tries to figure out if the gateway is * tries to figure out if the gateway is
......
...@@ -6,7 +6,7 @@ SYSTEM = ../tools/zSystem ...@@ -6,7 +6,7 @@ SYSTEM = ../tools/zSystem
zOBJECTS = $(HEAD) inflate.o unzip.o misc.o zOBJECTS = $(HEAD) inflate.o unzip.o misc.o
CFLAGS = -O6 -DSTDC_HEADERS $(TEST) CFLAGS = -O2 -DSTDC_HEADERS $(TEST)
.c.s: .c.s:
$(CC) $(CFLAGS) -S -o $*.s $< $(CC) $(CFLAGS) -S -o $*.s $<
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment