diff options
author | Linus Torvalds <torvalds@cc.helsinki.fi> | 1994-01-03 10:27:45 +0000 |
---|---|---|
committer | Nicolas Pitre <nico@cam.org> | 2007-08-19 14:19:24 -0400 |
commit | 8c14943430cec122e60f8065d087c095b5b54eca (patch) | |
tree | 236a6837f1ae3ed632edb61f2f46a020cc9f106c | |
parent | 5a09e4bfb5fefaf040962a64d74a4ac43b2d20e5 (diff) | |
download | archive-8c14943430cec122e60f8065d087c095b5b54eca.tar.gz |
ALPHA-pl14k
38 files changed, 1526 insertions, 528 deletions
@@ -1,6 +1,6 @@ VERSION = 0.99 PATCHLEVEL = 14 -ALPHA = i +ALPHA = k all: Version zImage @@ -189,8 +189,7 @@ zdisk: zImage zlilo: $(CONFIGURE) zImage if [ -f /vmlinuz ]; then mv /vmlinuz /vmlinuz.old; fi cat zImage > /vmlinuz - /etc/lilo/install - + if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi tools/zSystem: boot/head.o init/main.o tools/version.o linuxsubdirs $(LD) $(LDFLAGS) -T 100000 boot/head.o init/main.o tools/version.o \ @@ -221,6 +220,7 @@ net: dummy $(MAKE) linuxsubdirs SUBDIRS=net clean: + rm -f kernel/ksyms.lst rm -f core `find . -name '*.[oas]' -print` rm -f core `find . -name 'core' -print` rm -f zImage zSystem.map tools/zSystem tools/system @@ -82,7 +82,7 @@ bool 'AT1700 support' CONFIG_AT1700 n #bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n #bool 'Cabletron E21xx support (not recommended)' CONFIG_E21 n bool 'D-Link DE600 pocket adaptor support' CONFIG_DE600 n -#bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP n +bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP n fi * bool 'Sony CDU31A CDROM driver support' CONFIG_CDU31A n diff --git a/drivers/block/hd.c b/drivers/block/hd.c index b4dd66a..4391cc3 100644 --- a/drivers/block/hd.c +++ b/drivers/block/hd.c @@ -85,12 +85,6 @@ static struct hd_struct hd[MAX_HD<<6]={{0,0},}; static int hd_sizes[MAX_HD<<6] = {0, }; static int hd_blocksizes[MAX_HD<<6] = {0, }; -#define port_read(port,buf,nr) \ -__asm__("cld;rep;insw": :"d" (port),"D" (buf),"c" (nr):"cx","di") - -#define port_write(port,buf,nr) \ -__asm__("cld;rep;outsw": :"d" (port),"S" (buf),"c" (nr):"cx","si") - #if (HD_DELAY > 0) unsigned long read_timer(void) { @@ -339,7 +333,7 @@ static void read_intr(void) do_hd_request(); return; ok_to_read: - port_read(HD_DATA,CURRENT->buffer,256); + insw(HD_DATA,CURRENT->buffer,256); CURRENT->errors = 0; CURRENT->buffer += 512; CURRENT->sector++; @@ -398,7 +392,7 @@ ok_to_write: end_request(1); if (i > 0) { SET_INTR(&write_intr); - port_write(HD_DATA,CURRENT->buffer,256); + outsw(HD_DATA,CURRENT->buffer,256); sti(); } else { #if (HD_DELAY > 0) @@ -508,7 +502,7 @@ repeat: bad_rw_intr(); goto repeat; } - port_write(HD_DATA,CURRENT->buffer,256); + outsw(HD_DATA,CURRENT->buffer,256); sti(); return; } diff --git a/drivers/char/console.c b/drivers/char/console.c index a19a7a5..0823dc7 100644 --- a/drivers/char/console.c +++ b/drivers/char/console.c @@ -233,8 +233,8 @@ static unsigned char * translations[] = { "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" " !\"#$%&'()*+,-./0123456789:;<=>?" "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^ " - "\004\261\007\007\007\007\370\361\040\007\331\277\332\300\305\007" - "\007\304\007\007\303\264\301\302\263\007\007\007\007\007\234\0" + "\004\261\007\007\007\007\370\361\007\007\331\277\332\300\305\304" + "\304\304\137\137\303\264\301\302\263\363\362\343\330\234\007\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\040\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376" diff --git a/drivers/char/serial.c b/drivers/char/serial.c index cb7a649..c25c17b 100644 --- a/drivers/char/serial.c +++ b/drivers/char/serial.c @@ -25,6 +25,7 @@ #include <linux/serial.h> #include <linux/interrupt.h> #include <linux/config.h> +#include <linux/major.h> #include <linux/string.h> #include <linux/fcntl.h> #include <linux/ptrace.h> @@ -1580,7 +1581,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, * If this is a callout device, then just make sure the normal * device isn't being used. */ - if (MAJOR(filp->f_rdev) == 5) { + if (MAJOR(filp->f_rdev) == TTYAUX_MAJOR) { if (info->flags & ASYNC_NORMAL_ACTIVE) return -EBUSY; if ((info->flags & ASYNC_CALLOUT_ACTIVE) && @@ -1694,7 +1695,7 @@ int rs_open(struct tty_struct *tty, struct file * filp) tty->start = rs_start; tty->hangup = rs_hangup; if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { - if (MAJOR(filp->f_rdev) == 4) + if (MAJOR(filp->f_rdev) == TTY_MAJOR) *tty->termios = info->normal_termios; else *tty->termios = info->callout_termios; diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 1a2ac8b..44f094b 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -55,6 +55,8 @@ #include "vt_kern.h" +#define CONSOLE_DEV MKDEV(TTY_MAJOR,0) + #define MAX_TTYS 256 struct tty_struct *tty_table[MAX_TTYS]; @@ -239,13 +241,13 @@ void do_tty_hangup(struct tty_struct * tty, struct file_operations *fops) if (!tty) return; - dev = 0x0400 + tty->line; + dev = MKDEV(TTY_MAJOR,tty->line); for (filp = first_file, i=0; i<nr_files; i++, filp = filp->f_next) { - if (!filp->f_count) + if (!filp->f_count) continue; if (filp->f_rdev != dev) continue; - if (filp->f_inode && filp->f_inode->i_rdev == 0x0400) + if (filp->f_inode && filp->f_inode->i_rdev == CONSOLE_DEV) continue; if (filp->f_op != &tty_fops) continue; @@ -1031,7 +1033,7 @@ static int tty_read(struct inode * inode, struct file * file, char * buf, int co tty = TTY_TABLE(dev); if (!tty || (tty->flags & (1 << TTY_IO_ERROR))) return -EIO; - if ((inode->i_rdev != 0x0400) && /* don't stop on /dev/console */ + if ((inode->i_rdev != CONSOLE_DEV) && /* don't stop on /dev/console */ (tty->pgrp > 0) && (current->tty == dev) && (tty->pgrp != current->pgrp)) @@ -1056,7 +1058,7 @@ static int tty_write(struct inode * inode, struct file * file, char * buf, int c struct tty_struct * tty; dev = file->f_rdev; - is_console = (inode->i_rdev == 0x0400); + is_console = (inode->i_rdev == CONSOLE_DEV); if (MAJOR(dev) != TTY_MAJOR) { printk("tty_write: pseudo-major != TTY_MAJOR\n"); return -EINVAL; @@ -1396,7 +1398,7 @@ static int tty_open(struct inode * inode, struct file * filp) tty->session = current->session; tty->pgrp = current->pgrp; } - filp->f_rdev = 0x0400 | minor; /* Set it to something normal */ + filp->f_rdev = MKDEV(TTY_MAJOR,minor); /* Set it to something normal */ return 0; } diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index 44c5430..9b9d4db 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -38,7 +38,6 @@ static char *version = #include <errno.h> #include "dev.h" -#include "iow.h" #include "eth.h" #include "skbuff.h" #include "arp.h" @@ -321,7 +320,7 @@ el_start_xmit(struct sk_buff *skb, struct device *dev) inb(TX_STATUS); outb(0x00, RX_BUF_CLR); /* Set rx packet area to 0. */ outw(gp_start, GP_LOW); - port_write_b(DATAPORT,buf,skb->len); + outsb(DATAPORT,buf,skb->len); outw(gp_start, GP_LOW); outb(AX_XMIT, AX_CMD); /* Trigger xmit. */ dev->trans_start = jiffies; @@ -464,7 +463,7 @@ el_receive(struct device *dev) skb->len = pkt_len; skb->dev = dev; - port_read_b(DATAPORT, (void *)(skb+1), pkt_len); + insb(DATAPORT, (void *)(skb+1), pkt_len); #ifdef HAVE_NETIF_RX netif_rx(skb); diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index 64c4532..f55131f 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -50,7 +50,6 @@ static char *version = #include <memory.h> #include "dev.h" -#include "iow.h" #include "eth.h" #include "skbuff.h" #include "arp.h" diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index f0898d2..d517cd4 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -33,16 +33,6 @@ static char *version = "3c509.c:pl13t 11/24/93 becker@super.org\n"; #include "skbuff.h" #include "arp.h" -#ifndef port_read -#include "iow.h" -#endif - -/* These should be in <asm/io.h>. */ -#define port_read_l(port,buf,nr) \ -__asm__("cld;rep;insl": :"d" (port),"D" (buf),"c" (nr):"cx","di") -#define port_write_l(port,buf,nr) \ -__asm__("cld;rep;outsl": :"d" (port),"S" (buf),"c" (nr):"cx","si") - #ifndef HAVE_ALLOC_SKB #define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority) #endif @@ -415,7 +405,7 @@ el3_start_xmit(struct sk_buff *skb, struct device *dev) outw(skb->len, ioaddr + TX_FIFO); outw(0x00, ioaddr + TX_FIFO); /* ... and the packet rounded to a doubleword. */ - port_write_l(ioaddr + TX_FIFO, (void *)(skb+1), (skb->len + 3) >> 2); + outsl(ioaddr + TX_FIFO, (void *)(skb+1), (skb->len + 3) >> 2); dev->trans_start = jiffies; if (inw(ioaddr + TX_FREE) > 1536) { @@ -588,7 +578,7 @@ el3_rx(struct device *dev) skb->dev = dev; /* 'skb+1' points to the start of sk_buff data area. */ - port_read_l(ioaddr+RX_FIFO, (void *)(skb+1), + insl(ioaddr+RX_FIFO, (void *)(skb+1), (pkt_len + 3) >> 2); #ifdef HAVE_NETIF_RX diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index fe619c8..d31cd66 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -38,7 +38,6 @@ static char *version = #include <memory.h> #include "dev.h" -#include "iow.h" #include "eth.h" #include "skbuff.h" #include "arp.h" @@ -426,7 +425,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev) outb(0x00, ioaddr + TX_INTR); outw(length, ioaddr + DATAPORT); - port_write(ioaddr + DATAPORT, buf, (length + 1) >> 1); + outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1); lp->tx_queue++; lp->tx_queue_len += length + 2; @@ -553,7 +552,7 @@ net_rx(struct device *dev) skb->dev = dev; /* 'skb+1' points to the start of sk_buff data area. */ - port_read(ioaddr + DATAPORT, (void *)(skb+1), (pkt_len + 1) >> 1); + insw(ioaddr + DATAPORT, (void *)(skb+1), (pkt_len + 1) >> 1); if (net_debug > 5) { int i; diff --git a/drivers/net/atp.c b/drivers/net/atp.c new file mode 100644 index 0000000..f753c79 --- /dev/null +++ b/drivers/net/atp.c @@ -0,0 +1,789 @@ +/* atp.c: Attached (pocket) ethernet adaptor driver for linux. */ +/* + Written 1993 by Donald Becker. + Copyright 1993 United States Government as represented by the Director, + National Security Agency. This software may only be used and distributed + according to the terms of the GNU Public License as modified by SRC, + incorported herein by reference. + + The author may be reached as becker@super.org or + C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715 + +*/ + +static char *version = + "atp.c:v0.02 12/22/93 Donald Becker (becker@super.org)\n"; + +/* + This file is a device driver for the RealTek (aka AT-Lan-Tec) pocket + ethernet adaptor. This is a common low-cost OEM pocket ethernet + adaptor, sold under many names. + + Sources: + This driver was written from the packet driver assembly code provided by + Vincent Bono of AT-Lan-Tec. Ever try to figure out how a complicated + device works just from the assembly code? It ain't pretty. The following + description is written based on guesses and writing lots of special-purpose + code to test my theorized operation. + + Theory of Operation + + The RTL8002 adaptor seems to be built around a custom spin of the SEEQ + controller core. It probably has a 16K or 64K internal packet buffer, of + which the first 4K is devoted to transmit and the rest to receive. + The controller maintains the queue of received packet and the packet buffer + access pointer internally, with only 'reset to beginning' and 'skip to next + packet' commands visible. The transmit packet queue holds two (or more?) + packets: both 'retransmit this packet' (due to collision) and 'transmit next + packet' commands must be started by hand. + + The station address is stored in a standard bit-serial EEPROM which must be + read (ughh) by the device driver. (Provisions have been made for + substituting a 74S288 PROM, but I haven't gotten reports of any models + using it.) Unlike built-in devices, a pocket adaptor can temporarily lose + power without indication to the device driver. The major effect is that + the station address, receive filter (promiscuous, etc.) and transceiver + must be reset. + + The controller itself has 16 registers, some of which use only the lower + bits. The registers are read and written 4 bits at a time. The four bit + register address is presented on the data lines along with a few additional + timing and control bits. The data is then read from status port or written + to the data port. + + Since the bulk data transfer of the actual packets through the slow + parallel port dominates the driver's running time, four distinct data + (non-register) transfer modes are provided by the adaptor, two in each + direction. In the first mode timing for the nibble transfers is + provided through the data port. In the second mode the same timing is + provided through the control port. In either case the data is read from + the status port and written to the data port, just as it is accessing + registers. + + In addition to the basic data transfer methods, several more are modes are + created by adding some delay by doing multiple reads of the data to allow + it to stabilize. This delay seems to be needed on most machines. + + The data transfer mode is stored in the 'dev->if_port' field. Its default + value is '4'. It may be overriden at boot-time using the third parameter + to the "ether=..." initialization. + + The header file <atp.h> provides inline functions that encapsulate the + register and data access methods. These functions are hand-tuned to + generate reasonable object code. This header file also documents my + interpretations of the device registers. +*/ + +#include <linux/config.h> /* Used only to override default values. */ +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/fcntl.h> +#include <linux/interrupt.h> +#include <linux/ptrace.h> +#include <linux/ioport.h> +#include <linux/in.h> +#include <linux/malloc.h> +#include <linux/string.h> +#include <asm/system.h> +#include <asm/bitops.h> +#include <asm/io.h> +#include <asm/dma.h> +#include <errno.h> + +#include "dev.h" +#include "eth.h" +#include "skbuff.h" +#include "arp.h" + +#include "atp.h" + +/* Compatibility definitions for earlier kernel versions. */ +#ifndef HAVE_AUTOIRQ +/* From auto_irq.c, in ioport.h for later versions. */ +extern void autoirq_setup(int waittime); +extern int autoirq_report(int waittime); +/* The map from IRQ number (as passed to the interrupt handler) to + 'struct device'. */ +extern struct device *irq2dev_map[16]; +#endif + +#ifndef HAVE_ALLOC_SKB +#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority) +#define kfree_skbmem(addr, size) kfree_s(addr,size); +#endif + +#ifndef HAVE_PORTRESERVE +#define check_region(ioaddr, size) 0 +#define snarf_region(ioaddr, size); do ; while (0) +#endif + +/* use 0 for production, 1 for verification, >2 for debug */ +#ifndef NET_DEBUG +#define NET_DEBUG 4 +#endif +static unsigned int net_debug = NET_DEBUG; + +/* The number of low I/O ports used by the ethercard. */ +#define ETHERCARD_TOTAL_SIZE 3 + +/* Index to functions, as function prototypes. */ + +extern int atp_probe(struct device *dev); + +static int atp_probe1(struct device *dev, short ioaddr); +static void init_dev(struct device *dev); +static void get_node_ID(struct device *dev); +static unsigned short eeprom_op(short ioaddr, unsigned int cmd); +static int net_open(struct device *dev); +static void hardware_init(struct device *dev); +static void write_packet(short ioaddr, int length, unsigned char *packet, int mode); +static void trigger_send(short ioaddr, int length); +static int net_send_packet(struct sk_buff *skb, struct device *dev); +static void net_interrupt(int reg_ptr); +static void net_rx(struct device *dev); +static void read_block(short ioaddr, int length, unsigned char *buffer, int data_mode); +static int net_close(struct device *dev); +static struct enet_statistics *net_get_stats(struct device *dev); +#ifdef HAVE_MULTICAST +static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); +#endif + + +/* 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 == 1, always return failure. + If dev->base_addr == 2, alloate space for the device and return success + (detachable devices only). + */ +int +atp_init(struct device *dev) +{ + int *port, ports[] = {0x378, 0x278, 0x3bc, 0}; + int base_addr = dev->base_addr; + + if (base_addr > 0x1ff) /* Check a single specified location. */ + return atp_probe1(dev, base_addr); + else if (base_addr == 1) /* Don't probe at all. */ + return ENXIO; + + for (port = ports; *port; port++) { + int ioaddr = *port; + outb(0x57, ioaddr + PAR_DATA); + if (inb(ioaddr + PAR_DATA) != 0x57) + continue; + if (atp_probe1(dev, ioaddr) == 0) + return 0; + } + + return ENODEV; +} + +static int atp_probe1(struct device *dev, short ioaddr) +{ + int saved_ctrl_reg, status; + + outb(0xff, ioaddr + PAR_DATA); + /* Save the original value of the Control register, in case we guessed + wrong. */ + saved_ctrl_reg = inb(ioaddr + PAR_CONTROL); + /* IRQEN=0, SLCTB=high INITB=high, AUTOFDB=high, STBB=high. */ + outb(0x04, ioaddr + PAR_CONTROL); + write_reg_high(ioaddr, CMR1, CMR1h_RESET); + eeprom_delay(2048); + status = read_nibble(ioaddr, CMR1); + + if ((status & 0x78) != 0x08) { + /* The pocket adaptor probe failed, restore the control register. */ + outb(saved_ctrl_reg, ioaddr + PAR_CONTROL); + return 1; + } + status = read_nibble(ioaddr, CMR2_h); + if ((status & 0x78) != 0x10) { + outb(saved_ctrl_reg, ioaddr + PAR_CONTROL); + return 1; + } + /* Find the IRQ used by triggering an interrupt. */ + write_reg_byte(ioaddr, CMR2, 0x01); /* No accept mode, IRQ out. */ + write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE); /* Enable Tx and Rx. */ + + /* Omit autoIRQ routine for now. Use "table lookup" instead. Uhgggh. */ + if (ioaddr == 0x378) + dev->irq = 7; + else + dev->irq = 5; + write_reg_high(ioaddr, CMR1, CMR1h_TxRxOFF); /* Diable Tx and Rx units. */ + write_reg(ioaddr, CMR2, CMR2_NULL); + + dev->base_addr = ioaddr; + + /* Read the station address PROM. */ + get_node_ID(dev); + + printk("%s: Pocket adaptor found at %#3x, IRQ %d, SAPROM " + "%02X:%02X:%02X:%02X:%02X:%02X.\n", dev->name, dev->base_addr, + dev->irq, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + + /* Leave the hardware in a reset state. */ + write_reg_high(ioaddr, CMR1, CMR1h_RESET); + + if (net_debug) + printk(version); + + /* Initialize the device structure. */ + init_dev(dev); + dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); + memset(dev->priv, 0, sizeof(struct net_local)); + + + { + struct net_local *lp = (struct net_local *)dev->priv; + lp->addr_mode = CMR2h_Normal; + } + + /* For the ATP adaptor the "if_port" is really the data transfer mode. */ + dev->if_port = (dev->mem_start & 0xf) ? dev->mem_start & 0x7 : 4; + if (dev->mem_end & 0xf) + net_debug = dev->mem_end & 7; + + dev->open = net_open; + dev->stop = net_close; + dev->hard_start_xmit = net_send_packet; + dev->get_stats = net_get_stats; +#ifdef HAVE_MULTICAST + dev->set_multicast_list = &set_multicast_list; +#endif + + return 0; +} + +/* Fill in the fields of the device structure with ethernet-generic values. + This should be in a common file instead of per-driver. */ +static void init_dev(struct device *dev) +{ + int i; + + for (i = 0; i < DEV_NUMBUFFS; i++) + dev->buffs[i] = NULL; + + dev->hard_header = eth_header; + dev->add_arp = eth_add_arp; + dev->queue_xmit = dev_queue_xmit; + dev->rebuild_header = eth_rebuild_header; + dev->type_trans = eth_type_trans; + + dev->type = ARPHRD_ETHER; + dev->hard_header_len = ETH_HLEN; + dev->mtu = 1500; /* eth_mtu */ + dev->addr_len = ETH_ALEN; + for (i = 0; i < ETH_ALEN; i++) { + dev->broadcast[i]=0xff; + } + + /* 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 = sizeof(unsigned long); +} + +/* Read the station address PROM, usually a word-wide EEPROM. */ +static void get_node_ID(struct device *dev) +{ + short ioaddr = dev->base_addr; + int sa_offset = 0; + int i; + + write_reg(ioaddr, CMR2, CMR2_EEPROM); /* Point to the EEPROM control registers. */ + + /* Some adaptors have the station address at offset 15 instead of offset + zero. Check for it, and fix it if needed. */ + if (eeprom_op(ioaddr, EE_READ(0)) == 0xffff) + sa_offset = 15; + + for (i = 0; i < 3; i++) + ((unsigned short *)dev->dev_addr)[i] = + ntohs(eeprom_op(ioaddr, EE_READ(sa_offset + i))); + + write_reg(ioaddr, CMR2, CMR2_NULL); +} + +/* + An EEPROM read command starts by shifting out 0x60+address, and then + shifting in the serial data. See the NatSemi databook for details. + * ________________ + * CS : __| + * ___ ___ + * CLK: ______| |___| | + * __ _______ _______ + * DI : __X_______X_______X + * DO : _________X_______X + */ + +static unsigned short eeprom_op(short ioaddr, unsigned int cmd) +{ + unsigned eedata_out = 0; + int num_bits = EE_CMD_SIZE; + + while (--num_bits >= 0) { + char outval = test_bit(num_bits, &cmd) ? EE_DATA_WRITE : 0; + write_reg_high(ioaddr, PROM_CMD, outval | EE_CLK_LOW); + eeprom_delay(5); + write_reg_high(ioaddr, PROM_CMD, outval | EE_CLK_HIGH); + eedata_out <<= 1; + if (read_nibble(ioaddr, PROM_DATA) & EE_DATA_READ) + eedata_out++; + eeprom_delay(5); + } + write_reg_high(ioaddr, PROM_CMD, EE_CLK_LOW & ~EE_CS); + return eedata_out; +} + + +/* Open/initialize the board. This is called (in the current kernel) + sometime after booting when the 'ifconfig' program is run. + + This routine sets everything up anew at each open, even + registers that "should" only need to be set once at boot, so that + there is non-reboot way to recover if something goes wrong. + + This is an attachable device: if there is no dev->priv entry then it wasn't + probed for at boot-time, and we need to probe for it again. + */ +static int net_open(struct device *dev) +{ + + /* The interrupt line is turned off (tri-stated) when the device isn't in + use. That's especially important for "attached" interfaces where the + port or interrupt may be shared. */ + if (irq2dev_map[dev->irq] != 0 + || (irq2dev_map[dev->irq] = dev) == 0 + || request_irq(dev->irq, &net_interrupt)) { + return -EAGAIN; + } + + hardware_init(dev); + dev->start = 1; + return 0; +} + +/* This routine resets the hardware. We initialize everything, assuming that + the hardware may have been temporarily detacted. */ +static void hardware_init(struct device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + int ioaddr = dev->base_addr; + int i; + + write_reg_high(ioaddr, CMR1, CMR1h_RESET); + + for (i = 0; i < 6; i++) + write_reg_byte(ioaddr, PAR0 + i, dev->dev_addr[i]); + + write_reg_high(ioaddr, CMR2, lp->addr_mode); + + if (net_debug > 2) { + printk("%s: Reset: current Rx mode %d.\n", dev->name, + (read_nibble(ioaddr, CMR2_h) >> 3) & 0x0f); + } + + write_reg(ioaddr, CMR2, CMR2_IRQOUT); + write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE); + + /* Enable the interrupt line from the serial port. */ + outb(Ctrl_SelData + Ctrl_IRQEN, ioaddr + PAR_CONTROL); + + /* Unmask the interesting interrupts. */ + write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK); + write_reg_high(ioaddr, IMR, ISRh_RxErr); + + lp->tx_unit_busy = 0; + lp->pac_cnt_in_tx_buf = 0; + lp->saved_tx_size = 0; + + dev->tbusy = 0; + dev->interrupt = 0; +} + +static void trigger_send(short ioaddr, int length) +{ + write_reg_byte(ioaddr, TxCNT0, length & 0xff); + write_reg(ioaddr, TxCNT1, length >> 8); + write_reg(ioaddr, CMR1, CMR1_Xmit); +} + +static void write_packet(short ioaddr, int length, unsigned char *packet, int data_mode) +{ + length = (length + 1) & ~1; /* Round up to word length. */ + outb(EOC+MAR, ioaddr + PAR_DATA); + if ((data_mode & 1) == 0) { + /* Write the packet out, starting with the write addr. */ + outb(WrAddr+MAR, ioaddr + PAR_DATA); + do { + write_byte_mode0(ioaddr, *packet++); + } while (--length > 0) ; + } else { + /* Write the packet out in slow mode. */ + unsigned char outbyte = *packet++; + + outb(Ctrl_LNibWrite + Ctrl_IRQEN, ioaddr + PAR_CONTROL); + outb(WrAddr+MAR, ioaddr + PAR_DATA); + + outb((outbyte & 0x0f)|0x40, ioaddr + PAR_DATA); + outb(outbyte & 0x0f, ioaddr + PAR_DATA); + outbyte >>= 4; + outb(outbyte & 0x0f, ioaddr + PAR_DATA); + outb(Ctrl_HNibWrite + Ctrl_IRQEN, ioaddr + PAR_CONTROL); + while (--length > 0) + write_byte_mode1(ioaddr, *packet++); + } + /* Terminate the Tx frame. End of write: ECB. */ + outb(0xff, ioaddr + PAR_DATA); + outb(Ctrl_HNibWrite | Ctrl_SelData | Ctrl_IRQEN, ioaddr + PAR_CONTROL); +} + +static int +net_send_packet(struct sk_buff *skb, struct device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + int ioaddr = dev->base_addr; + + if (dev->tbusy) { + /* If we get here, some higher level has decided we are broken. + There should really be a "kick me" function call instead. */ + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 5) + return 1; + printk("%s: transmit timed out, %s?\n", dev->name, + inb(ioaddr + PAR_CONTROL) & 0x10 ? "network cable problem" + : "IRQ conflict"); + lp->stats.tx_errors++; + /* Try to restart the adaptor. */ + hardware_init(dev); + dev->tbusy=0; + dev->trans_start = jiffies; + } + + /* If some higher layer thinks we've missed an tx-done interrupt + we are passed NULL. Caution: dev_tint() handles the cli()/sti() + itself. */ + if (skb == NULL) { + dev_tint(dev); + return 0; + } + + /* For ethernet, fill in the header. This should really be done by a + higher level, rather than duplicated for each ethernet adaptor. */ + if (!skb->arp && dev->rebuild_header(skb+1, dev)) { + skb->dev = dev; + arp_queue (skb); + return 0; + } + skb->arp=1; + + /* Block a timer-based transmit from overlapping. This could better be + done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ + if (set_bit(0, (void*)&dev->tbusy) != 0) + printk("%s: Transmitter access conflict.\n", dev->name); + else { + short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + unsigned char *buf = (void *)(skb+1); + int flags; + + /* Disable interrupts by writing 0x00 to the Interrupt Mask Register. + This sequence must not be interrupted by an incoming packet. */ + save_flags(flags); + cli(); + write_reg(ioaddr, IMR, 0); + write_reg_high(ioaddr, IMR, 0); + restore_flags(flags); + + write_packet(ioaddr, length, buf, dev->if_port); + + lp->pac_cnt_in_tx_buf++; + if (lp->tx_unit_busy == 0) { + trigger_send(ioaddr, length); + lp->saved_tx_size = 0; /* Redundent */ + lp->re_tx = 0; + lp->tx_unit_busy = 1; + } else + lp->saved_tx_size = length; + + dev->trans_start = jiffies; + /* Re-enable the LPT interrupts. */ + write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK); + write_reg_high(ioaddr, IMR, ISRh_RxErr); + } + + if (skb->free) + kfree_skb (skb, FREE_WRITE); + + return 0; +} + +/* The typical workload of the driver: + Handle the network interface interrupts. */ +static void +net_interrupt(int reg_ptr) +{ + int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2); + struct device *dev = (struct device *)(irq2dev_map[irq]); + struct net_local *lp; + int ioaddr, status, boguscount = 20; + static int num_tx_since_rx = 0; + + if (dev == NULL) { + printk ("ATP_interrupt(): irq %d for unknown device.\n", irq); + return; + } + dev->interrupt = 1; + + ioaddr = dev->base_addr; + lp = (struct net_local *)dev->priv; + + /* Disable additional spurious interrupts. */ + outb(Ctrl_SelData, ioaddr + PAR_CONTROL); + + /* The adaptor's output is currently the IRQ line, switch it to data. */ + write_reg(ioaddr, CMR2, CMR2_NULL); + write_reg(ioaddr, IMR, 0); + + if (net_debug > 5) printk("%s: In interrupt ", dev->name); + while (--boguscount > 0) { + status = read_nibble(ioaddr, ISR); + if (net_debug > 5) printk("loop status %02x..", status); + + if (status & (ISR_RxOK<<3)) { + write_reg(ioaddr, ISR, ISR_RxOK); /* Clear the Rx interrupt. */ + do { + int read_status = read_nibble(ioaddr, CMR1); + if (net_debug > 6) + printk("handling Rx packet %02x..", read_status); + /* We acknowledged the normal Rx interrupt, so if the interrupt + is still outstanding we must have a Rx error. */ + if (read_status & (CMR1_IRQ << 3)) { /* Overrun. */ + lp->stats.rx_over_errors++; + /* Set to no-accept mode long enough to remove a packet. */ + write_reg_high(ioaddr, CMR2, CMR2h_OFF); + net_rx(dev); + /* Clear the interrupt and return to normal Rx mode. */ + write_reg_high(ioaddr, ISR, ISRh_RxErr); + write_reg_high(ioaddr, CMR2, lp->addr_mode); + } else if ((read_status & (CMR1_BufEnb << 3)) == 0) { + net_rx(dev); + dev->last_rx = jiffies; + num_tx_since_rx = 0; + } else + break; + } while (--boguscount > 0); + } else if (status & ((ISR_TxErr + ISR_TxOK)<<3)) { + if (net_debug > 6) printk("handling Tx done.."); + /* Clear the Tx interrupt. We should check for too many failures + and reinitialize the adaptor. */ + write_reg(ioaddr, ISR, ISR_TxErr + ISR_TxOK); + if (status & (ISR_TxErr<<3)) { + lp->stats.collisions++; + if (++lp->re_tx > 15) { + lp->stats.tx_aborted_errors++; + hardware_init(dev); + break; + } + /* Attempt to retransmit. */ + if (net_debug > 6) printk("attempting to ReTx"); + write_reg(ioaddr, CMR1, CMR1_ReXmit + CMR1_Xmit); + } else { + /* Finish up the transmit. */ + lp->stats.tx_packets++; + lp->pac_cnt_in_tx_buf--; + if ( lp->saved_tx_size) { + trigger_send(ioaddr, lp->saved_tx_size); + lp->saved_tx_size = 0; + lp->re_tx = 0; + } else + lp->tx_unit_busy = 0; + dev->tbusy = 0; + mark_bh(INET_BH); /* Inform upper layers. */ + } + num_tx_since_rx++; + } else if (num_tx_since_rx > 8 + && jiffies > dev->last_rx + 100) { + if (net_debug > 2) + printk("%s: Missed packet? No Rx after %d Tx and %d jiffies" + " status %02x CMR1 %02x.\n", dev->name, + num_tx_since_rx, jiffies - dev->last_rx, status, + (read_nibble(ioaddr, CMR1) >> 3) & 15); + lp->stats.rx_missed_errors++; + hardware_init(dev); + num_tx_since_rx = 0; + break; + } else + break; + } + + /* Tell the adaptor that it can go back to using the output line as IRQ. */ + write_reg(ioaddr, CMR2, CMR2_IRQOUT); + /* Enable the physical interrupt line, which is sure to be low until.. */ + outb(Ctrl_SelData + Ctrl_IRQEN, ioaddr + PAR_CONTROL); + /* .. we enable the interrupt sources. */ + write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK); + write_reg_high(ioaddr, IMR, ISRh_RxErr); /* Hmmm, really needed? */ + + if (net_debug > 5) printk("exiting interrupt.\n"); + + dev->interrupt = 0; + + return; +} + +/* We have a good packet(s), get it/them out of the buffers. */ +static void net_rx(struct device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + int ioaddr = dev->base_addr; +#ifdef notdef + ushort header[4]; +#else + struct rx_header rx_head; +#endif + + /* Process the received packet. */ + outb(EOC+MAR, ioaddr + PAR_DATA); + read_block(ioaddr, 8, (unsigned char*)&rx_head, dev->if_port); + if (net_debug > 5) + printk(" rx_count %04x %04x %04x %04x..", rx_head.pad, + rx_head.rx_count, rx_head.rx_status, rx_head.cur_addr); + if ((rx_head.rx_status & 0x77) != 0x01) { + lp->stats.rx_errors++; + /* Ackkk! I don't have any documentation on what the error bits mean! + The best I can do is slap the device around a bit. */ + if (net_debug > 3) printk("%s: Unknown ATP Rx error %04x.\n", + dev->name, rx_head.rx_status); + hardware_init(dev); + return; + } else { + /* Malloc up new buffer. */ + int pkt_len = (rx_head.rx_count & 0x7ff) - 4; /* The "-4" is omits the FCS (CRC). */ + int sksize = sizeof(struct sk_buff) + pkt_len; + struct sk_buff *skb; + + skb = alloc_skb(sksize, GFP_ATOMIC); + if (skb == NULL) { + printk("%s: Memory squeeze, dropping packet.\n", dev->name); + lp->stats.rx_dropped++; + goto done; + } + skb->mem_len = sksize; + skb->mem_addr = skb; + skb->len = pkt_len; + skb->dev = dev; + + /* 'skb+1' points to the start of sk_buff data area. */ + read_block(ioaddr, pkt_len, (unsigned char *)(skb + 1), dev->if_port); + + if (net_debug > 6) { + unsigned char *data = (unsigned char *)(skb + 1); + 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[6], data[7], data[8], data[9], data[10], data[11], + data[12], data[13]); + } + +#ifdef HAVE_NETIF_RX + netif_rx(skb); +#else + skb->lock = 0; + if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) { + kfree_s(skb, sksize); + lp->stats.rx_dropped++; + break; + } +#endif + lp->stats.rx_packets++; + } + done: + write_reg(ioaddr, CMR1, CMR1_NextPkt); + return; +} + +static void read_block(short ioaddr, int length, unsigned char *p, int data_mode) +{ + + if (data_mode <= 3) { /* Mode 0 or 1 */ + outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL); + outb(length == 8 ? RdAddr | HNib | MAR : RdAddr | MAR, + ioaddr + PAR_DATA); + if (data_mode <= 1) { /* Mode 0 or 1 */ + do *p++ = read_byte_mode0(ioaddr); while (--length > 0); + } else /* Mode 2 or 3 */ + do *p++ = read_byte_mode2(ioaddr); while (--length > 0); + } else if (data_mode <= 5) + do *p++ = read_byte_mode4(ioaddr); while (--length > 0); + else + do *p++ = read_byte_mode6(ioaddr); while (--length > 0); + + outb(EOC+HNib+MAR, ioaddr + PAR_DATA); + outb(Ctrl_SelData, ioaddr + PAR_CONTROL); +} + +/* The inverse routine to net_open(). */ +static int +net_close(struct device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + int ioaddr = dev->base_addr; + + dev->tbusy = 1; + dev->start = 0; + + /* Flush the Tx and disable Rx here. */ + lp->addr_mode = CMR2h_OFF; + write_reg_high(ioaddr, CMR2, CMR2h_OFF); + + /* Free the IRQ line. */ + outb(0x00, ioaddr + PAR_CONTROL); + free_irq(dev->irq); + irq2dev_map[dev->irq] = 0; + + /* Leave the hardware in a reset state. */ + write_reg_high(ioaddr, CMR1, CMR1h_RESET); + + return 0; +} + +/* Get the current statistics. This may be called with the card open or + closed. */ +static struct enet_statistics * +net_get_stats(struct device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + return &lp->stats; +} + +#ifdef HAVE_MULTICAST +/* Set or clear the multicast filter for this adaptor. + num_addrs == -1 Promiscuous mode, receive all packets + num_addrs == 0 Normal mode, clear multicast list + num_addrs > 0 Multicast mode, receive normal and MC packets, and do + best-effort filtering. + */ +static void +set_multicast_list(struct device *dev, int num_addrs, void *addrs) +{ + struct net_local *lp = (struct net_local *)dev->priv; + short ioaddr = dev->base_addr; + lp->addr_mode = num_addrs ? CMR2h_PROMISC : CMR2h_Normal; + write_reg_high(ioaddr, CMR2, lp->addr_mode); +} +#endif + +/* + * Local variables: + * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c atp.c" + * version-control: t + * kept-new-versions: 5 + * tab-width: 4 + * End: + */ diff --git a/drivers/net/atp.h b/drivers/net/atp.h new file mode 100644 index 0000000..6988eae --- /dev/null +++ b/drivers/net/atp.h @@ -0,0 +1,264 @@ +#include <linux/if_ether.h> +#include <linux/types.h> +#include <asm/io.h> + +struct net_local { +#ifdef __KERNEL__ + struct enet_statistics stats; +#endif + ushort saved_tx_size; + unsigned char + re_tx, /* Number of packet retransmissions. */ + tx_unit_busy, + addr_mode, /* Current Rx filter e.g. promiscuous, etc. */ + pac_cnt_in_tx_buf; +}; + +struct rx_header { + ushort pad; /* The first read is always corrupted. */ + ushort rx_count; + ushort rx_status; /* Unknown bit assignments :-<. */ + ushort cur_addr; /* Apparently the current buffer address(?) */ +}; + +#define PAR_DATA 0 +#define PAR_STATUS 1 +#define PAR_CONTROL 2 + +#define Ctrl_LNibRead 0x08 /* LP_PSELECP */ +#define Ctrl_HNibRead 0 +#define Ctrl_LNibWrite 0x08 /* LP_PSELECP */ +#define Ctrl_HNibWrite 0 +#define Ctrl_SelData 0x04 /* LP_PINITP */ +#define Ctrl_IRQEN 0x10 /* LP_PINTEN */ + +#define EOW 0xE0 +#define EOC 0xE0 +#define WrAddr 0x40 /* Set address of EPLC read, write register. */ +#define RdAddr 0xC0 +#define HNib 0x10 + +enum page0_regs +{ + /* The first six registers hold the ethernet physical station address. */ + PAR0 = 0, PAR1 = 1, PAR2 = 2, PAR3 = 3, PAR4 = 4, PAR5 = 5, + TxCNT0 = 6, TxCNT1 = 7, /* The transmit byte count. */ + TxSTAT = 8, RxSTAT = 9, /* Tx and Rx status. */ + ISR = 10, IMR = 11, /* Interrupt status and mask. */ + CMR1 = 12, /* Command register 1. */ + CMR2 = 13, /* Command register 2. */ + MAR = 14, /* Memory address register. */ + CMR2_h = 0x1d, }; + +enum eepage_regs +{ PROM_CMD = 6, PROM_DATA = 7 }; /* Note that PROM_CMD is in the "high" bits. */ + + +#define ISR_TxOK 0x01 +#define ISR_RxOK 0x04 +#define ISR_TxErr 0x02 +#define ISRh_RxErr 0x11 /* ISR, high nibble */ + +#define CMR1h_RESET 0x04 /* Reset. */ +#define CMR1h_RxENABLE 0x02 /* Rx unit enable. */ +#define CMR1h_TxENABLE 0x01 /* Tx unit enable. */ +#define CMR1h_TxRxOFF 0x00 +#define CMR1_ReXmit 0x08 /* Trigger a retransmit. */ +#define CMR1_Xmit 0x04 /* Trigger a transmit. */ +#define CMR1_IRQ 0x02 /* Interrupt active. */ +#define CMR1_BufEnb 0x01 /* Enable the buffer(?). */ +#define CMR1_NextPkt 0x01 /* Enable the buffer(?). */ + +#define CMR2_NULL 8 +#define CMR2_IRQOUT 9 +#define CMR2_RAMTEST 10 +#define CMR2_EEPROM 12 /* Set to page 1, for reading the EEPROM. */ + +#define CMR2h_OFF 0 /* No accept mode. */ +#define CMR2h_Physical 1 /* Accept a physical address match only. */ +#define CMR2h_Normal 2 /* Accept physical and broadcast address. */ +#define CMR2h_PROMISC 3 /* Promiscuous mode. */ + +/* An inline function used below: it differs from inb() by explicitly return an unsigned + char, saving a truncation. */ +extern inline unsigned char inbyte(unsigned short port) +{ + unsigned char _v; + __asm__ __volatile__ ("inb %w1,%b0" :"=a" (_v):"d" (port)); + return _v; +} + +/* Read register OFFSET. + This command should aways be terminated with read_end(). */ +extern inline unsigned char read_nibble(short port, unsigned char offset) +{ + unsigned char retval; + outb(EOC+offset, port + PAR_DATA); + outb(RdAddr+offset, port + PAR_DATA); + inbyte(port + PAR_STATUS); /* Settling time delay */ + retval = inbyte(port + PAR_STATUS); + outb(EOC+offset, port + PAR_DATA); + + return retval; +} + +/* Functions for bulk data read. The interrupt line is always disabled. */ +/* Get a byte using read mode 0, reading data from the control lines. */ +extern inline unsigned char read_byte_mode0(short ioaddr) +{ + unsigned char low_nib; + + outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL); + inbyte(ioaddr + PAR_STATUS); + low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f; + outb(Ctrl_HNibRead, ioaddr + PAR_CONTROL); + inbyte(ioaddr + PAR_STATUS); /* Settling time delay -- needed! */ + inbyte(ioaddr + PAR_STATUS); /* Settling time delay -- needed! */ + return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0); +} + +/* The same as read_byte_mode0(), but does multiple inb()s for stability. */ +extern inline unsigned char read_byte_mode2(short ioaddr) +{ + unsigned char low_nib; + + outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL); + inbyte(ioaddr + PAR_STATUS); + low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f; + outb(Ctrl_HNibRead, ioaddr + PAR_CONTROL); + inbyte(ioaddr + PAR_STATUS); /* Settling time delay -- needed! */ + return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0); +} + +/* Read a byte through the data register. */ +extern inline unsigned char read_byte_mode4(short ioaddr) +{ + unsigned char low_nib; + + outb(RdAddr | MAR, ioaddr + PAR_DATA); + low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f; + outb(RdAddr | HNib | MAR, ioaddr + PAR_DATA); + return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0); +} + +/* Read a byte through the data register, double reading to allow settling. */ +extern inline unsigned char read_byte_mode6(short ioaddr) +{ + unsigned char low_nib; + + outb(RdAddr | MAR, ioaddr + PAR_DATA); + inbyte(ioaddr + PAR_STATUS); + low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f; + outb(RdAddr | HNib | MAR, ioaddr + PAR_DATA); + inbyte(ioaddr + PAR_STATUS); + return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0); +} + +extern inline void +write_reg(short port, unsigned char reg, unsigned char value) +{ + unsigned char outval; + outb(EOC | reg, port + PAR_DATA); + outval = WrAddr | reg; + outb(outval, port + PAR_DATA); + outb(outval, port + PAR_DATA); /* Double write for PS/2. */ + + outval &= 0xf0; + outval |= value; + outb(outval, port + PAR_DATA); + outval &= 0x1f; + outb(outval, port + PAR_DATA); + outb(outval, port + PAR_DATA); + + outb(EOC | outval, port + PAR_DATA); +} + +extern inline void +write_reg_high(short port, unsigned char reg, unsigned char value) +{ + unsigned char outval = EOC | HNib | reg; + + outb(outval, port + PAR_DATA); + outval &= WrAddr | HNib | 0x0f; + outb(outval, port + PAR_DATA); + outb(outval, port + PAR_DATA); /* Double write for PS/2. */ + + outval = WrAddr | HNib | value; + outb(outval, port + PAR_DATA); + outval &= HNib | 0x0f; /* HNib | value */ + outb(outval, port + PAR_DATA); + outb(outval, port + PAR_DATA); + + outb(EOC | HNib | outval, port + PAR_DATA); +} + +/* Write a byte out using nibble mode. The low nibble is written first. */ +extern inline void +write_reg_byte(short port, unsigned char reg, unsigned char value) +{ + unsigned char outval; + outb(EOC | reg, port + PAR_DATA); /* Reset the address register. */ + outval = WrAddr | reg; + outb(outval, port + PAR_DATA); + outb(outval, port + PAR_DATA); /* Double write for PS/2. */ + + outb((outval & 0xf0) | (value & 0x0f), port + PAR_DATA); + outb(value & 0x0f, port + PAR_DATA); + value >>= 4; + outb(value, port + PAR_DATA); + outb(0x10 | value, port + PAR_DATA); + outb(0x10 | value, port + PAR_DATA); + + outb(EOC | value, port + PAR_DATA); /* Reset the address register. */ +} + +/* + * Bulk data writes to the packet buffer. The interrupt line remains enabled. + * The first, faster method uses only the dataport (data modes 0, 2 & 4). + * The second (backup) method uses data and control regs (modes 1, 3 & 5). + * It should only be needed when there is skew between the individual data + * lines. + */ +extern inline void write_byte_mode0(short ioaddr, unsigned char value) +{ + outb(value & 0x0f, ioaddr + PAR_DATA); + outb((value>>4) | 0x10, ioaddr + PAR_DATA); +} + +extern inline void write_byte_mode1(short ioaddr, unsigned char value) +{ + outb(value & 0x0f, ioaddr + PAR_DATA); + outb(Ctrl_IRQEN | Ctrl_LNibWrite, ioaddr + PAR_CONTROL); + outb((value>>4) | 0x10, ioaddr + PAR_DATA); + outb(Ctrl_IRQEN | Ctrl_HNibWrite, ioaddr + PAR_CONTROL); +} + +/* Write 16bit VALUE to the packet buffer: the same as above just doubled. */ +extern inline void write_word_mode0(short ioaddr, unsigned short value) +{ + outb(value & 0x0f, ioaddr + PAR_DATA); + value >>= 4; + outb((value & 0x0f) | 0x10, ioaddr + PAR_DATA); + value >>= 4; + outb(value & 0x0f, ioaddr + PAR_DATA); + value >>= 4; + outb((value & 0x0f) | 0x10, ioaddr + PAR_DATA); +} + +/* EEPROM_Ctrl bits. */ +#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */ +#define EE_CS 0x02 /* EEPROM chip select. */ +#define EE_CLK_HIGH 0x12 +#define EE_CLK_LOW 0x16 +#define EE_DATA_WRITE 0x01 /* EEPROM chip data in. */ +#define EE_DATA_READ 0x08 /* EEPROM chip data out. */ + +/* Delay between EEPROM clock transitions. */ +#define eeprom_delay(ticks) \ +do { int _i = 40; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0) + +/* The EEPROM commands include the alway-set leading bit. */ +#define EE_WRITE_CMD(offset) (((5 << 6) + (offset)) << 17) +#define EE_READ(offset) (((6 << 6) + (offset)) << 17) +#define EE_ERASE(offset) (((7 << 6) + (offset)) << 17) +#define EE_CMD_SIZE 27 /* The command+address+data size. */ diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index 41c2480..7daab32 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -50,7 +50,6 @@ static char *version = #include <memory.h> #include "dev.h" -#include "iow.h" #include "eth.h" #include "skbuff.h" #include "arp.h" @@ -701,7 +700,7 @@ set_multicast_list(struct device *dev, int num_addrs, void *addrs) by the list of multicast addresses to be accepted. */ outw(SET_MC_CMD + 6, ioaddr + WRITE_PTR); outw(num_addrs * 6, ioaddr); - port_write(ioaddr, addrs, num_addrs*3); /* 3 = addr len in words */ + outsw(ioaddr, addrs, num_addrs*3); /* 3 = addr len in words */ /* We must trigger a whole 586 reset due to a bug. */ } else { /* Not written yet, this requires expanding the init_words config @@ -770,11 +769,11 @@ init_82586_mem(struct device *dev) /* Place the write pointer at 0xfff6 (address-aliased to 0xfffff6). */ outw(0xfff6, ioaddr + WRITE_PTR); - port_write(ioaddr, init_words, sizeof(init_words)>>1); + outsw(ioaddr, init_words, sizeof(init_words)>>1); /* Fill in the station address. */ outw(SA_OFFSET, ioaddr + WRITE_PTR); - port_write(ioaddr, dev->dev_addr, 3); + outsw(ioaddr, dev->dev_addr, 3); /* The Tx-block list is written as needed. We just set up the values. */ #ifdef initial_text_tx @@ -882,7 +881,7 @@ hardware_send_packet(struct device *dev, void *buf, short length) /* Output the packet using the write pointer. Hmmm, it feels a little like a 3c501! */ - port_write(ioaddr + DATAPORT, buf, (length + 1) >> 1); + outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1); /* Set the old command link pointing to this send packet. */ outw(lp->tx_cmd_link, ioaddr + WRITE_PTR); @@ -961,7 +960,7 @@ eexp_rx(struct device *dev) outw(data_buffer_addr + 10, ioaddr + READ_PTR); - port_read(ioaddr, (void *)(skb+1), (pkt_len + 1) >> 1); + insw(ioaddr, (void *)(skb+1), (pkt_len + 1) >> 1); #ifdef HAVE_NETIF_RX netif_rx(skb); diff --git a/drivers/net/hp.c b/drivers/net/hp.c index f6304f1..eda01d1 100644 --- a/drivers/net/hp.c +++ b/drivers/net/hp.c @@ -1,19 +1,19 @@ /* hp.c: A HP LAN ethernet driver for linux. */ /* - Written 1993 by Donald Becker. - Copyright 1993 United States Government as represented by the - Director, National Security Agency. This software may be used and - distributed according to the terms of the GNU Public License, - incorporated herein by reference. + Written 1993 by Donald Becker. + Copyright 1993 United States Government as represented by the + Director, National Security Agency. This software may be used and + distributed according to the terms of the GNU Public License, + incorporated herein by reference. - This is a driver for the HP LAN adaptors. + This is a driver for the HP LAN adaptors. - The Author may be reached as becker@super.org or - C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715 + The Author may be reached as becker@super.org or + C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715 */ static char *version = - "hp.c:v0.99.13f 10/16/93 Donald Becker (becker@super.org)\n"; + "hp.c:v0.99.14a 12/2/93 Donald Becker (becker@super.org)\n"; #include <linux/config.h> #include <linux/kernel.h> @@ -22,182 +22,194 @@ static char *version = #include <linux/ioport.h> #include <asm/system.h> #include <asm/io.h> -#ifndef port_read -#include "iow.h" -#endif #include "dev.h" #include "8390.h" -#define HP_DATAPORT 0x0c /* "Remote DMA" data port. */ -#define HP_ID 0x07 +#ifndef HAVE_PORTRESERVE +#define check_region(ioaddr, size) 0 +#define snarf_region(ioaddr, size); do ; while (0) +#endif + +#define HP_IO_EXTENT 32 + +#define HP_DATAPORT 0x0c /* "Remote DMA" data port. */ +#define HP_ID 0x07 #define HP_CONFIGURE 0x08 /* Configuration register. */ -#define HP_RUN 0x01 /* 1 == Run, 0 == reset. */ -#define HP_IRQ 0x0E /* Mask for software-configured IRQ line. */ -#define HP_DATAON 0x10 /* Turn on dataport */ -#define NIC_OFFSET 0x10 /* Offset the 8390 registers. */ +#define HP_RUN 0x01 /* 1 == Run, 0 == reset. */ +#define HP_IRQ 0x0E /* Mask for software-configured IRQ line. */ +#define HP_DATAON 0x10 /* Turn on dataport */ +#define NIC_OFFSET 0x10 /* Offset the 8390 registers. */ -#define HP_START_PG 0x00 /* First page of TX buffer */ +#define HP_START_PG 0x00 /* First page of TX buffer */ #define HP_8BSTOP_PG 0x80 /* Last page +1 of RX ring */ -#define HP_16BSTOP_PG 0xFF /* Last page +1 of RX ring */ +#define HP_16BSTOP_PG 0xFF /* Same, for 16 bit cards. */ int hp_probe(struct device *dev); -int hpprobe1(int ioaddr, struct device *dev); +int hpprobe1(struct device *dev, int ioaddr); static void hp_reset_8390(struct device *dev); static int hp_block_input(struct device *dev, int count, - char *buf, int ring_offset); + char *buf, int ring_offset); static void hp_block_output(struct device *dev, int count, - const unsigned char *buf, const start_page); + const unsigned char *buf, const start_page); static void hp_init_card(struct device *dev); /* 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}; -/* Probe for an HP LAN adaptor. - Also initialize the card and fill in STATION_ADDR with the station - address. */ +/* Probe for an HP LAN adaptor. + Also initialize the card and fill in STATION_ADDR with the station + address. */ int hp_probe(struct device *dev) { - int *port, ports[] = {0x300, 0x320, 0x340, 0x280, 0x2C0, 0x200, 0x240, 0}; - short ioaddr = dev->base_addr; + int *port, ports[] = {0x300, 0x320, 0x340, 0x280, 0x2C0, 0x200, 0x240, 0}; + short ioaddr = dev->base_addr; - if (ioaddr > 0x1ff) /* Check a single specified location. */ - return ! hpprobe1(ioaddr, dev); - else if (ioaddr > 0) /* Don't probe at all. */ + if (ioaddr > 0x1ff) /* Check a single specified location. */ + return hpprobe1(dev, ioaddr); + else if (ioaddr > 0) /* Don't probe at all. */ return ENXIO; - for (port = &ports[0]; *port; port++) { -#ifdef HAVE_PORTRESERVE - if (check_region(*port, 32)) - continue; -#endif - if (inb_p(*port) != 0xff && hpprobe1(*port, dev)) { - return 0; + for (port = &ports[0]; *port; port++) { + if (check_region(*port, HP_IO_EXTENT)) + continue; + if (hpprobe1(dev, *port) == 0) { + return 0; + } } - } - dev->base_addr = ioaddr; - return ENODEV; + return ENODEV; } -int hpprobe1(int ioaddr, struct device *dev) +int hpprobe1(struct device *dev, int ioaddr) { - int i; - unsigned char *station_addr = dev->dev_addr; - int tmp; - - /* Check for the HP physical address, 08 00 09 xx xx xx. */ - if (inb(ioaddr) != 0x08 - || inb(ioaddr+1) != 0x00 - || inb(ioaddr+2) != 0x09) - return 0; - /* This really isn't good enough, we may pick up HP LANCE boards also! */ - - ethdev_init(dev); - - ei_status.tx_start_page = HP_START_PG; - ei_status.rx_start_page = HP_START_PG + TX_PAGES; - /* Set up the rest of the parameters. */ - if ((tmp = inb(ioaddr + HP_ID)) & 0x80) { - ei_status.name = "HP27247"; - ei_status.word16 = 1; - ei_status.stop_page = HP_16BSTOP_PG; /* Safe (if small) value */ - } else { - ei_status.name = "HP27250"; - ei_status.word16 = 0; - ei_status.stop_page = HP_8BSTOP_PG; - } - - printk("%s: %s at %#3x,", dev->name, ei_status.name, ioaddr); - - for(i = 0; i < ETHER_ADDR_LEN; i++) - printk(" %2.2x", station_addr[i] = inb(ioaddr + i)); - - - /* Set the base address to point to the NIC, not the "real" base! */ - dev->base_addr = ioaddr + NIC_OFFSET; - - /* Snarf the interrupt now. Someday this could be moved to open(). */ - if (dev->irq < 2) { - int irq_16list[] = { 11, 10, 5, 3, 4, 7, 9, 0}; - int irq_8list[] = { 7, 5, 3, 4, 9, 0}; - int *irqp = ei_status.word16 ? irq_16list : irq_8list; - do { - if (request_irq (dev->irq = *irqp, NULL) != -EBUSY) { - autoirq_setup(0); - /* Twinkle the interrupt, and check if it's seen. */ - outb_p(irqmap[dev->irq] | HP_RUN, ioaddr + HP_CONFIGURE); - outb_p( 0x00 | HP_RUN, ioaddr + HP_CONFIGURE); - if (dev->irq == autoirq_report(0) /* It's a good IRQ line! */ - && request_irq (dev->irq, &ei_interrupt) == 0) { - printk(" selecting IRQ %d.\n", dev->irq); - break; - } - } - } while (*++irqp); - if (*irqp == 0) { - printk(" no free IRQ lines.\n"); - return 0; - } - } else { - if (dev->irq == 2) - dev->irq = 9; - if (irqaction(dev->irq, &ei_sigaction)) { - printk (" unable to get IRQ %d.\n", dev->irq); - return 0; - } - } - -#ifdef HAVE_PORTRESERVE - snarf_region(ioaddr, 32); -#endif + int status, i, board_id, wordmode; + char *name; + unsigned char *station_addr = dev->dev_addr; + + /* Check for the HP physical address, 08 00 09 xx xx xx. */ + if (inb(ioaddr) != 0x08 + || inb(ioaddr+1) != 0x00 + || inb(ioaddr+2) != 0x09) + return ENODEV; + + /* 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; + + /* Set up the parameters based on the board ID. + If you have additional mappings, please mail them to becker@super.org. */ + if ((board_id = inb(ioaddr + HP_ID)) & 0x80) { + name = "HP27247"; + wordmode = 1; + } else { + name = "HP27250"; + wordmode = 0; + } + + /* Grab the region so we can find another board if something fails. */ + snarf_region(ioaddr, HP_IO_EXTENT); + + printk("%s: %s (ID %02x) at %#3x,", dev->name, name, board_id, ioaddr); + + for(i = 0; i < ETHER_ADDR_LEN; i++) + printk(" %2.2x", station_addr[i] = inb(ioaddr + i)); + + /* Snarf the interrupt now. Someday this could be moved to open(). */ + if (dev->irq < 2) { + int irq_16list[] = { 11, 10, 5, 3, 4, 7, 9, 0}; + int irq_8list[] = { 7, 5, 3, 4, 9, 0}; + int *irqp = wordmode ? irq_16list : irq_8list; + do { + int irq = *irqp; + if (request_irq (irq, NULL) != -EBUSY) { + autoirq_setup(0); + /* Twinkle the interrupt, and check if it's seen. */ + outb_p(irqmap[irq] | HP_RUN, ioaddr + HP_CONFIGURE); + outb_p( 0x00 | HP_RUN, ioaddr + HP_CONFIGURE); + if (irq == autoirq_report(0) /* It's a good IRQ line! */ + && request_irq (irq, &ei_interrupt) == 0) { + printk(" selecting IRQ %d.\n", irq); + dev->irq = *irqp; + break; + } + } + } while (*++irqp); + if (*irqp == 0) { + printk(" no free IRQ lines.\n"); + return EBUSY; + } + } else { + if (dev->irq == 2) + dev->irq = 9; + if (irqaction(dev->irq, &ei_sigaction)) { + printk (" unable to get IRQ %d.\n", dev->irq); + return EBUSY; + } + } + + if (ei_debug > 1) + printk(version); - if (ei_debug > 1) - printk(version); + /* Set the base address to point to the NIC, not the "real" base! */ + dev->base_addr = ioaddr + NIC_OFFSET; - ei_status.reset_8390 = &hp_reset_8390; - ei_status.block_input = &hp_block_input; - ei_status.block_output = &hp_block_output; - hp_init_card(dev); - return dev->base_addr; + ethdev_init(dev); + + ei_status.name = name; + ei_status.word16 = wordmode; + ei_status.tx_start_page = HP_START_PG; + ei_status.rx_start_page = HP_START_PG + TX_PAGES; + ei_status.stop_page = wordmode ? HP_16BSTOP_PG : HP_8BSTOP_PG; + + ei_status.reset_8390 = &hp_reset_8390; + ei_status.block_input = &hp_block_input; + ei_status.block_output = &hp_block_output; + hp_init_card(dev); + + return 0; } static void hp_reset_8390(struct device *dev) { - int hp_base = dev->base_addr - NIC_OFFSET; - int saved_config = inb_p(hp_base + HP_CONFIGURE); - int reset_start_time = jiffies; - - if (ei_debug > 1) printk("resetting the 8390 time=%d...", jiffies); - outb_p(0x00, hp_base + HP_CONFIGURE); - ei_status.txing = 0; - - sti(); - /* We shouldn't use the boguscount for timing, but this hasn't been - checked yet, and you could hang your machine if jiffies break... */ - { - int boguscount = 150000; - while(jiffies - reset_start_time < 2) - if (boguscount-- < 0) { - printk("jiffy failure (t=%d)...", jiffies); - break; - } - } - - outb_p(saved_config, hp_base + HP_CONFIGURE); - while ((inb_p(hp_base+NIC_OFFSET+EN0_ISR) & ENISR_RESET) == 0) - if (jiffies - reset_start_time > 2) { - printk("%s: hp_reset_8390() did not complete.\n", dev->name); - return; + int hp_base = dev->base_addr - NIC_OFFSET; + int saved_config = inb_p(hp_base + HP_CONFIGURE); + int reset_start_time = jiffies; + + if (ei_debug > 1) printk("resetting the 8390 time=%d...", jiffies); + outb_p(0x00, hp_base + HP_CONFIGURE); + ei_status.txing = 0; + + sti(); + /* We shouldn't use the boguscount for timing, but this hasn't been + checked yet, and you could hang your machine if jiffies break... */ + { + int boguscount = 150000; + while(jiffies - reset_start_time < 2) + if (boguscount-- < 0) { + printk("jiffy failure (t=%d)...", jiffies); + break; + } } - if (ei_debug > 1) printk("8390 reset done (%d).", jiffies); + + outb_p(saved_config, hp_base + HP_CONFIGURE); + while ((inb_p(hp_base+NIC_OFFSET+EN0_ISR) & ENISR_RESET) == 0) + if (jiffies - reset_start_time > 2) { + printk("%s: hp_reset_8390() did not complete.\n", dev->name); + return; + } + if (ei_debug > 1) printk("8390 reset done (%d).", jiffies); } -/* Block input and output, similar to the Crynwr packet driver. If you +/* Block input and output, similar to the Crynwr packet driver. If you porting to a new ethercard look at the packet driver source for hints. The HP LAN doesn't use shared memory -- we put the packet out through the "remote DMA" dataport. */ @@ -205,111 +217,112 @@ hp_reset_8390(struct device *dev) static int hp_block_input(struct device *dev, int count, char *buf, int ring_offset) { - int nic_base = dev->base_addr; - int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE); - int xfer_count = count; - - outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE); - outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base); - outb_p(count & 0xff, nic_base + EN0_RCNTLO); - outb_p(count >> 8, nic_base + EN0_RCNTHI); - outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO); - outb_p(ring_offset >> 8, nic_base + EN0_RSARHI); - outb_p(E8390_RREAD+E8390_START, nic_base); - if (ei_status.word16) { - port_read(nic_base - NIC_OFFSET + HP_DATAPORT,buf,count>>1); - if (count & 0x01) - buf[count-1] = inb(nic_base - NIC_OFFSET + HP_DATAPORT), xfer_count++; - } else { - port_read_b(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count); - } - /* This is for the ALPHA version only, remove for later releases. */ - if (ei_debug > 0) { /* DMA termination address check... */ - int high = inb_p(nic_base + EN0_RSARHI); - int low = inb_p(nic_base + EN0_RSARLO); - int addr = (high << 8) + low; - /* Check only the lower 8 bits so we can ignore ring wrap. */ - if (((ring_offset + xfer_count) & 0xff) != (addr & 0xff)) - printk("%s: RX transfer address mismatch, %#4.4x vs. %#4.4x (actual).\n", - dev->name, ring_offset + xfer_count, addr); - } - outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE); - return ring_offset + count; + int nic_base = dev->base_addr; + int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE); + int xfer_count = count; + + outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE); + outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base); + outb_p(count & 0xff, nic_base + EN0_RCNTLO); + outb_p(count >> 8, nic_base + EN0_RCNTHI); + outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO); + outb_p(ring_offset >> 8, nic_base + EN0_RSARHI); + outb_p(E8390_RREAD+E8390_START, nic_base); + if (ei_status.word16) { + insw(nic_base - NIC_OFFSET + HP_DATAPORT,buf,count>>1); + if (count & 0x01) + buf[count-1] = inb(nic_base - NIC_OFFSET + HP_DATAPORT), xfer_count++; + } else { + insb(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count); + } + /* This is for the ALPHA version only, remove for later releases. */ + if (ei_debug > 0) { /* DMA termination address check... */ + int high = inb_p(nic_base + EN0_RSARHI); + int low = inb_p(nic_base + EN0_RSARLO); + int addr = (high << 8) + low; + /* Check only the lower 8 bits so we can ignore ring wrap. */ + if (((ring_offset + xfer_count) & 0xff) != (addr & 0xff)) + printk("%s: RX transfer address mismatch, %#4.4x vs. %#4.4x (actual).\n", + dev->name, ring_offset + xfer_count, addr); + } + outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE); + return ring_offset + count; } static void hp_block_output(struct device *dev, int count, - const unsigned char *buf, const start_page) + const unsigned char *buf, const start_page) { - int nic_base = dev->base_addr; - int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE); - - outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE); - /* Round the count up for word writes. Do we need to do this? - What effect will an odd byte count have on the 8390? - I should check someday. */ - if (ei_status.word16 && (count & 0x01)) - count++; - /* We should already be in page 0, but to be safe... */ - outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base); + int nic_base = dev->base_addr; + int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE); + + outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE); + /* Round the count up for word writes. Do we need to do this? + What effect will an odd byte count have on the 8390? + I should check someday. */ + if (ei_status.word16 && (count & 0x01)) + count++; + /* We should already be in page 0, but to be safe... */ + outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base); #ifdef ei8390_bug - /* Handle the read-before-write bug the same way as the - Crynwr packet driver -- the NatSemi method doesn't work. */ - outb_p(0x42, nic_base + EN0_RCNTLO); - outb_p(0, nic_base + EN0_RCNTHI); - outb_p(0xff, nic_base + EN0_RSARLO); - outb_p(0x00, nic_base + EN0_RSARHI); - outb_p(E8390_RREAD+E8390_START, EN_CMD); - /* Make certain that the dummy read has occured. */ - inb_p(0x61); - inb_p(0x61); + /* Handle the read-before-write bug the same way as the + Crynwr packet driver -- the NatSemi method doesn't work. */ + outb_p(0x42, nic_base + EN0_RCNTLO); + outb_p(0, nic_base + EN0_RCNTHI); + outb_p(0xff, nic_base + EN0_RSARLO); + outb_p(0x00, nic_base + EN0_RSARHI); + outb_p(E8390_RREAD+E8390_START, EN_CMD); + /* Make certain that the dummy read has occured. */ + inb_p(0x61); + inb_p(0x61); #endif - outb_p(count & 0xff, nic_base + EN0_RCNTLO); - outb_p(count >> 8, nic_base + EN0_RCNTHI); - outb_p(0x00, nic_base + EN0_RSARLO); - outb_p(start_page, nic_base + EN0_RSARHI); - - outb_p(E8390_RWRITE+E8390_START, nic_base); - if (ei_status.word16) { - /* Use the 'rep' sequence for 16 bit boards. */ - port_write(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count>>1); - } else { - port_write_b(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count); - } - - /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here -- it's broken! */ - - /* This is for the ALPHA version only, remove for later releases. */ - if (ei_debug > 0) { /* DMA termination address check... */ - int high = inb_p(nic_base + EN0_RSARHI); - int low = inb_p(nic_base + EN0_RSARLO); - int addr = (high << 8) + low; - if ((start_page << 8) + count != addr) - printk("%s: TX Transfer address mismatch, %#4.4x vs. %#4.4x.\n", - dev->name, (start_page << 8) + count, addr); - } - outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE); - return; + outb_p(count & 0xff, nic_base + EN0_RCNTLO); + outb_p(count >> 8, nic_base + EN0_RCNTHI); + outb_p(0x00, nic_base + EN0_RSARLO); + outb_p(start_page, nic_base + EN0_RSARHI); + + outb_p(E8390_RWRITE+E8390_START, nic_base); + if (ei_status.word16) { + /* Use the 'rep' sequence for 16 bit boards. */ + outsw(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count>>1); + } else { + outsb(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count); + } + + /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here -- it's broken! */ + + /* This is for the ALPHA version only, remove for later releases. */ + if (ei_debug > 0) { /* DMA termination address check... */ + int high = inb_p(nic_base + EN0_RSARHI); + int low = inb_p(nic_base + EN0_RSARLO); + int addr = (high << 8) + low; + if ((start_page << 8) + count != addr) + printk("%s: TX Transfer address mismatch, %#4.4x vs. %#4.4x.\n", + dev->name, (start_page << 8) + count, addr); + } + outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE); + return; } /* This function resets the ethercard if something screws up. */ static void hp_init_card(struct device *dev) { - int irq = dev->irq; - NS8390_init(dev, 0); - outb_p(irqmap[irq&0x0f] | HP_RUN, - dev->base_addr - NIC_OFFSET + HP_CONFIGURE); - return; + int irq = dev->irq; + NS8390_init(dev, 0); + outb_p(irqmap[irq&0x0f] | HP_RUN, + dev->base_addr - NIC_OFFSET + HP_CONFIGURE); + return; } /* * Local variables: - * compile-command: "gcc -D__KERNEL__ -Wall -O6 -I/usr/src/linux/net/inet -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 * kept-new-versions: 5 + * tab-width: 4 * End: */ diff --git a/drivers/net/iow.h b/drivers/net/iow.h index e186c45..6e15688 100644 --- a/drivers/net/iow.h +++ b/drivers/net/iow.h @@ -1,126 +1,6 @@ #ifndef _ASM_IOW_H #define _ASM_IOW_H -/* I added a few. Please add to the distributed files. -djb. */ -/* This file is copied 1:1 from /linux/include/asm/io.h, and changed all - al to ax, all inb to inw and all outb to outw (to get word in/out) - the four inlines here should be added to the original, and - then this one rm'd (and the #include "iow.h" in depca.c removed)... - Gruss PB -*/ -/* - * Thanks to James van Artsdalen for a better timing-fix than - * the two short jumps: using outb's to a nonexistent port seems - * to guarantee better timings even on fast machines. - * - * On the other hand, I'd like to be sure of a non-existent port: - * I feel a bit unsafe abou using 0x80. - * - * Linus - */ -/* This is the more general version of outw.. */ -extern inline void __outw(unsigned short value, unsigned short port) -{ -__asm__ __volatile__ ("outw %w0,%w1" - : /* no outputs */ - :"a" (value),"d" (port)); -} - -/* this is used for constant port numbers < 256.. */ -extern inline void __outwc(unsigned short value, unsigned short port) -{ -__asm__ __volatile__ ("outw %w0,%1" - : /* no outputs */ - :"a" (value),"i" (port)); -} - -/* general version of inw */ -extern inline unsigned int __inw(unsigned short port) -{ - unsigned int _v; -__asm__ __volatile__ ("inw %w1,%w0" - :"=a" (_v):"d" (port),"0" (0)); - return _v; -} - -/* inw with constant port nr 0-255 */ -extern inline unsigned int __inwc(unsigned short port) -{ - unsigned int _v; -__asm__ __volatile__ ("inw %1,%w0" - :"=a" (_v):"i" (port),"0" (0)); - return _v; -} - -extern inline void __outw_p(unsigned short value, unsigned short port) -{ -__asm__ __volatile__ ("outw %w0,%w1" - : /* no outputs */ - :"a" (value),"d" (port)); - SLOW_DOWN_IO; -} - -extern inline void __outwc_p(unsigned short value, unsigned short port) -{ -__asm__ __volatile__ ("outw %w0,%1" - : /* no outputs */ - :"a" (value),"i" (port)); - SLOW_DOWN_IO; -} - -extern inline unsigned int __inw_p(unsigned short port) -{ - unsigned int _v; -__asm__ __volatile__ ("inw %w1,%w0" - :"=a" (_v):"d" (port),"0" (0)); - SLOW_DOWN_IO; - return _v; -} - -extern inline unsigned int __inwc_p(unsigned short port) -{ - unsigned int _v; -__asm__ __volatile__ ("inw %1,%w0" - :"=a" (_v):"i" (port),"0" (0)); - SLOW_DOWN_IO; - return _v; -} - -/* - * Note that due to the way __builtin_constant_p() works, you - * - can't use it inside a inlien function (it will never be true) - * - you don't have to worry about side effects within the __builtin.. - */ -#define outw(val,port) \ -((__builtin_constant_p((port)) && (port) < 256) ? \ - __outwc((val),(port)) : \ - __outw((val),(port))) - -#define inw(port) \ -((__builtin_constant_p((port)) && (port) < 256) ? \ - __inwc(port) : \ - __inw(port)) - -#define outw_p(val,port) \ -((__builtin_constant_p((port)) && (port) < 256) ? \ - __outwc_p((val),(port)) : \ - __outw_p((val),(port))) - -#define inw_p(port) \ -((__builtin_constant_p((port)) && (port) < 256) ? \ - __inwc_p(port) : \ - __inw_p(port)) +/* no longer used */ #endif - -/* The word-wide I/O operations are more general, but require a halved - count. */ -#define port_read(port,buf,nr) \ -__asm__("cld;rep;insw": :"d" (port),"D" (buf),"c" (nr):"cx","di") -#define port_write(port,buf,nr) \ -__asm__("cld;rep;outsw": :"d" (port),"S" (buf),"c" (nr):"cx","si") - -#define port_read_b(port,buf,nr) \ -__asm__("cld;rep;insb": :"d" (port),"D" (buf),"c" (nr):"cx","di") -#define port_write_b(port,buf,nr) \ -__asm__("cld;rep;outsb": :"d" (port),"S" (buf),"c" (nr):"cx","si") diff --git a/drivers/net/lance.c b/drivers/net/lance.c index b80ecbd..4e9642b 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -14,7 +14,7 @@ C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715 */ -static char *version = "lance.c:v0.13s 11/15/93 becker@super.org\n"; +static char *version = "lance.c:v0.14g 12/21/93 becker@super.org\n"; #include <linux/config.h> #include <linux/kernel.h> @@ -30,7 +30,6 @@ static char *version = "lance.c:v0.13s 11/15/93 becker@super.org\n"; #include <asm/dma.h> #include "dev.h" -#include "iow.h" #include "eth.h" #include "skbuff.h" #include "arp.h" @@ -145,7 +144,7 @@ tx_full and tbusy flags. Reasonable default values are 4 Tx buffers, and 16 Rx buffers. That translates to 2 (4 == 2^^2) and 4 (16 == 2^^4). */ #ifndef LANCE_LOG_TX_BUFFERS -#define LANCE_LOG_TX_BUFFERS 2 +#define LANCE_LOG_TX_BUFFERS 4 #define LANCE_LOG_RX_BUFFERS 4 #endif @@ -224,7 +223,6 @@ unsigned long lance_init(unsigned long mem_start, unsigned long mem_end) { int *port, ports[] = {0x300, 0x320, 0x340, 0x360, 0}; - printk("lance_init(%#x, %#x).\n", mem_start, mem_end); for (port = &ports[0]; *port; port++) { int ioaddr = *port; @@ -336,7 +334,8 @@ static unsigned long lance_probe1(short ioaddr, unsigned long mem_start) dev->irq = autoirq_report(1); if (dev->irq) - printk(", probed IRQ %d, fixed at DMA %d.\n", dev->irq, dev->dma); + printk(", probed IRQ %d, fixed at DMA %d.\n", + dev->irq, dev->dma); else { printk(", failed to detect IRQ line.\n"); return mem_start; @@ -617,13 +616,6 @@ lance_interrupt(int reg_ptr) if (csr0 & 0x0200) { /* Tx-done interrupt */ int dirty_tx = lp->dirty_tx; - if (dirty_tx == lp->cur_tx - TX_RING_SIZE - && dev->tbusy) { - /* The ring is full, clear tbusy. */ - dev->tbusy = 0; - mark_bh(INET_BH); - } - while (dirty_tx < lp->cur_tx) { int entry = dirty_tx & TX_RING_MOD_MASK; int status = lp->tx_ring[entry].base; @@ -650,7 +642,7 @@ lance_interrupt(int reg_ptr) /* 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 - should always works. */ + should always work. */ if (databuff >= (void*)(&lp->tx_bounce_buffs[TX_RING_SIZE]) || databuff < (void*)(lp->tx_bounce_buffs)) { struct sk_buff *skb = ((struct sk_buff *)databuff) - 1; @@ -660,15 +652,21 @@ lance_interrupt(int reg_ptr) dirty_tx++; } - lp->dirty_tx = dirty_tx; - #ifndef final_version if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) { printk("out-of-sync dirty pointer, %d vs. %d.\n", dirty_tx, lp->cur_tx); - lp->dirty_tx += TX_RING_SIZE; + dirty_tx += TX_RING_SIZE; } #endif + + if (dev->tbusy && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) { + /* The ring is no longer full, clear tbusy. */ + dev->tbusy = 0; + mark_bh(INET_BH); + } + + lp->dirty_tx = dirty_tx; } if (csr0 & 0x8000) { diff --git a/drivers/net/ne.c b/drivers/net/ne.c index 0542a82..e198d55 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -17,7 +17,7 @@ /* Routines for the NatSemi-based designs (NE[12]000). */ static char *version = - "ne.c:v0.99-14g 12/21/93 Donald Becker (becker@super.org)\n"; + "ne.c:v0.99-14a 12/3/93 Donald Becker (becker@super.org)\n"; #include <linux/config.h> #include <linux/kernel.h> @@ -25,9 +25,6 @@ static char *version = #include <linux/errno.h> #include <asm/system.h> #include <asm/io.h> -#ifndef port_read -#include "iow.h" -#endif #include "dev.h" #include "8390.h" @@ -306,11 +303,11 @@ ne_block_input(struct device *dev, int count, char *buf, int ring_offset) outb_p(ring_offset >> 8, nic_base + EN0_RSARHI); outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD); if (ei_status.word16) { - port_read(NE_BASE + NE_DATAPORT,buf,count>>1); + insw(NE_BASE + NE_DATAPORT,buf,count>>1); if (count & 0x01) buf[count-1] = inb(NE_BASE + NE_DATAPORT), xfer_count++; } else { - port_read_b(NE_BASE + NE_DATAPORT, buf, count); + insb(NE_BASE + NE_DATAPORT, buf, count); } /* This was for the ALPHA version only, but enough people have @@ -385,9 +382,9 @@ ne_block_output(struct device *dev, int count, outb_p(E8390_RWRITE+E8390_START, nic_base + NE_CMD); if (ei_status.word16) { - port_write(NE_BASE + NE_DATAPORT, buf, count>>1); + outsw(NE_BASE + NE_DATAPORT, buf, count>>1); } else { - port_write_b(NE_BASE + NE_DATAPORT, buf, count); + outsb(NE_BASE + NE_DATAPORT, buf, count); } /* This was for the ALPHA version only, but enough people have diff --git a/drivers/net/skeleton.c b/drivers/net/skeleton.c index 48d64a8..760ca94 100644 --- a/drivers/net/skeleton.c +++ b/drivers/net/skeleton.c @@ -57,7 +57,6 @@ static char *version = #include <errno.h> #include "dev.h" -#include "iow.h" #include "eth.h" #include "skbuff.h" #include "arp.h" @@ -425,7 +424,7 @@ net_rx(struct device *dev) memcpy((unsigned char *) (skb + 1), (void*)dev->rmem_start, pkt_len); /* or */ - port_read(ioaddr, (void *)(skb+1), (pkt_len + 1) >> 1); + insw(ioaddr, (void *)(skb+1), (pkt_len + 1) >> 1); #ifdef HAVE_NETIF_RX netif_rx(skb); diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index 17010fb..4939e6f 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -333,17 +333,6 @@ All Rights Reserved\r\n\0 \r\n \r\n", 0x1029, 102 #define SIGNATURE_COUNT (sizeof( signatures ) / sizeof( struct signature )) -/* These defines are copied from kernel/blk_drv/hd.c */ - -#define insw( buf, count, port ) \ - __asm__ volatile \ - ("cld;rep;insw": :"d" (port),"D" (buf),"c" (count):"cx","di" ) - -#define outsw( buf, count, port ) \ - __asm__ volatile \ - ("cld;rep;outsw": :"d" (port),"S" (buf),"c" (count):"cx","si") - - static void do_pause( unsigned amount ) /* Pause for amount*10 milliseconds */ { unsigned long the_time = jiffies + amount; /* 0.01 seconds per jiffy */ @@ -1469,9 +1458,9 @@ void aha152x_intr( int irqno ) disp_ports(); #endif - outsw( ¤t_SC->cmnd, - COMMAND_SIZE(current_SC->cmnd[0])>>1, - DATAPORT ); + outsw( DATAPORT, + ¤t_SC->cmnd, + COMMAND_SIZE(current_SC->cmnd[0])>>1 ); #if defined(DEBUG_CMD) printk("FCNT=%d, STCNT=%d, ", GETPORT(FIFOSTAT), GETSTCNT() ); @@ -1763,7 +1752,7 @@ void aha152x_intr( int irqno ) { CLRBITS(DMACNTRL0, _8BIT ); data_count >>= 1; /* Number of words */ - insw( current_SC->SCp.ptr, data_count, DATAPORT ); + insw( DATAPORT, current_SC->SCp.ptr, data_count ); #if defined(DEBUG_DATAI) /* show what comes with the last transfer */ if(done) @@ -1892,7 +1881,7 @@ void aha152x_intr( int irqno ) { CLRBITS(DMACNTRL0, _8BIT ); data_count >>= 1; /* Number of words */ - outsw( current_SC->SCp.ptr, data_count, DATAPORT ); + outsw( DATAPORT, current_SC->SCp.ptr, data_count ); current_SC->SCp.ptr += 2 * data_count; current_SC->SCp.this_residual -= 2 * data_count; } diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c index b82f031..ac41368 100644 --- a/drivers/scsi/fdomain.c +++ b/drivers/scsi/fdomain.c @@ -325,36 +325,6 @@ struct signature { #define SIGNATURE_COUNT (sizeof( signatures ) / sizeof( struct signature )) -/* These functions are based on include/asm/io.h */ - -inline static unsigned short inw( unsigned short port ) -{ - unsigned short _v; - - __asm__ volatile ( "inw %1,%0" - :"=a" (_v):"d" ((unsigned short) port) ); - return _v; -} - -inline static void outw( unsigned short value, unsigned short port ) -{ - __asm__ volatile ( "outw %0,%1" - : :"a" ((unsigned short) value), - "d" ((unsigned short) port) ); -} - - -/* These defines are copied from kernel/blk_drv/hd.c */ - -#define insw( buf, count, port ) \ - __asm__ volatile \ - ("cld;rep;insw": :"d" (port),"D" (buf),"c" (count):"cx","di" ) - -#define outsw( buf, count, port ) \ - __asm__ volatile \ - ("cld;rep;outsw": :"d" (port),"S" (buf),"c" (count):"cx","si") - - static void print_banner( void ) { printk( "%s", fdomain_16x0_info() ); @@ -1113,7 +1083,7 @@ void fdomain_16x0_intr( int unused ) --current_SC->SCp.this_residual; } else { data_count >>= 1; - outsw( current_SC->SCp.ptr, data_count, Write_FIFO_port ); + outsw( Write_FIFO_port, current_SC->SCp.ptr, data_count ); current_SC->SCp.ptr += 2 * data_count; current_SC->SCp.this_residual -= 2 * data_count; } @@ -1146,7 +1116,7 @@ void fdomain_16x0_intr( int unused ) --current_SC->SCp.this_residual; } else { data_count >>= 1; /* Number of words */ - insw( current_SC->SCp.ptr, data_count, Read_FIFO_port ); + insw( Read_FIFO_port, current_SC->SCp.ptr, data_count ); current_SC->SCp.ptr += 2 * data_count; current_SC->SCp.this_residual -= 2 * data_count; } diff --git a/drivers/sound/sb16_dsp.c b/drivers/sound/sb16_dsp.c index e8e25cc..f3f18a1 100644 --- a/drivers/sound/sb16_dsp.c +++ b/drivers/sound/sb16_dsp.c @@ -220,7 +220,7 @@ sb16_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg,int local) case SOUND_PCM_WRITE_CHANNELS: if (local) return dsp_set_stereo(arg-1)+1; - return IOCTL_OUT (arg, dsp_set_stereo(IOCTL_IN (arg)-1))+1; + return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg) - 1) + 1); case SOUND_PCM_READ_CHANNELS: if (local) diff --git a/fs/minix/inode.c b/fs/minix/inode.c index 97e2920..bc4b16c 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -25,16 +25,43 @@ void minix_put_inode(struct inode *inode) minix_free_inode(inode); } +static void minix_commit_super (struct super_block * sb, + struct minix_super_block * ms) +{ + sb->u.minix_sb.s_sbh->b_dirt = 1; + sb->s_dirt = 0; +} + +void minix_write_super (struct super_block * sb) +{ + struct minix_super_block * ms; + + if (!(sb->s_flags & MS_RDONLY)) { + ms = sb->u.minix_sb.s_ms; + + if (ms->s_state & MINIX_VALID_FS) + ms->s_state &= ~MINIX_VALID_FS; + minix_commit_super (sb, ms); + } + sb->s_dirt = 0; +} + + void minix_put_super(struct super_block *sb) { int i; lock_super(sb); + if (!(sb->s_flags & MS_RDONLY)) { + sb->u.minix_sb.s_ms->s_state = sb->u.minix_sb.s_mount_state; + sb->u.minix_sb.s_sbh->b_dirt = 1; + } sb->s_dev = 0; for(i = 0 ; i < MINIX_I_MAP_SLOTS ; i++) brelse(sb->u.minix_sb.s_imap[i]); for(i = 0 ; i < MINIX_Z_MAP_SLOTS ; i++) brelse(sb->u.minix_sb.s_zmap[i]); + brelse (sb->u.minix_sb.s_sbh); unlock_super(sb); return; } @@ -45,11 +72,46 @@ static struct super_operations minix_sops = { minix_write_inode, minix_put_inode, minix_put_super, - NULL, + minix_write_super, minix_statfs, - NULL + minix_remount }; +int minix_remount (struct super_block * sb, int * flags, char * data) +{ + struct minix_super_block * ms; + + ms = sb->u.minix_sb.s_ms; + if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) + return 0; + if (*flags & MS_RDONLY) { + if (ms->s_state & MINIX_VALID_FS || + !(sb->u.minix_sb.s_mount_state & MINIX_VALID_FS)) + return 0; + /* Mounting a rw partition read-only. */ + ms->s_state = sb->u.minix_sb.s_mount_state; + sb->u.minix_sb.s_sbh->b_dirt = 1; + sb->s_dirt = 1; + minix_commit_super (sb, ms); + } + else { + /* Mount a partition which is read-only, read-write. */ + sb->u.minix_sb.s_mount_state = ms->s_state; + ms->s_state &= ~MINIX_VALID_FS; + sb->u.minix_sb.s_sbh->b_dirt = 1; + sb->s_dirt = 1; + + if (!(sb->u.minix_sb.s_mount_state & MINIX_VALID_FS)) + printk ("MINIX-fs warning: remounting unchecked fs, " + "running fsck is recommended.\n"); + else if ((sb->u.minix_sb.s_mount_state & MINIX_ERROR_FS)) + printk ("MINIX-fs warning: remounting fs with errors, " + "running fsck is recommended.\n"); + } + return 0; +} + + struct super_block *minix_read_super(struct super_block *s,void *data, int silent) { @@ -67,6 +129,9 @@ struct super_block *minix_read_super(struct super_block *s,void *data, return NULL; } ms = (struct minix_super_block *) bh->b_data; + s->u.minix_sb.s_ms = ms; + s->u.minix_sb.s_sbh = bh; + s->u.minix_sb.s_mount_state = ms->s_state; s->s_blocksize = 1024; s->s_blocksize_bits = 10; s->u.minix_sb.s_ninodes = ms->s_ninodes; @@ -77,7 +142,6 @@ struct super_block *minix_read_super(struct super_block *s,void *data, s->u.minix_sb.s_log_zone_size = ms->s_log_zone_size; s->u.minix_sb.s_max_size = ms->s_max_size; s->s_magic = ms->s_magic; - brelse(bh); if (s->s_magic == MINIX_SUPER_MAGIC) { s->u.minix_sb.s_dirsize = 16; s->u.minix_sb.s_namelen = 14; @@ -87,9 +151,9 @@ struct super_block *minix_read_super(struct super_block *s,void *data, } else { s->s_dev = 0; unlock_super(s); + brelse(bh); if (!silent) - printk("VFS: Can't find a minix filesystem on dev 0x%04x.\n", - dev); + printk("VFS: Can't find a minix filesystem on dev 0x%04x.\n", dev); return NULL; } for (i=0;i < MINIX_I_MAP_SLOTS;i++) @@ -114,21 +178,34 @@ struct super_block *minix_read_super(struct super_block *s,void *data, brelse(s->u.minix_sb.s_zmap[i]); s->s_dev=0; unlock_super(s); + brelse(bh); printk("MINIX-fs: bad superblock or unable to read bitmaps\n"); return NULL; } set_bit(0,s->u.minix_sb.s_imap[0]->b_data); set_bit(0,s->u.minix_sb.s_zmap[0]->b_data); + unlock_super(s); /* set up enough so that it can read an inode */ s->s_dev = dev; s->s_op = &minix_sops; s->s_mounted = iget(s,MINIX_ROOT_INO); - unlock_super(s); if (!s->s_mounted) { s->s_dev = 0; + brelse(bh); printk("MINIX-fs: get root inode failed\n"); return NULL; } + if (!(s->s_flags & MS_RDONLY)) { + ms->s_state &= ~MINIX_VALID_FS; + bh->b_dirt = 1; + s->s_dirt = 1; + } + if (!(s->u.minix_sb.s_mount_state & MINIX_VALID_FS)) + printk ("MINIX-fs: mounting unchecked file system, " + "running fsck is recommended.\n"); + else if (s->u.minix_sb.s_mount_state & MINIX_ERROR_FS) + printk ("MINIX-fs: mounting file system with errors, " + "running fsck is recommended.\n"); return s; } diff --git a/include/asm/io.h b/include/asm/io.h index b510959..e9ad940 100644 --- a/include/asm/io.h +++ b/include/asm/io.h @@ -52,6 +52,16 @@ __IN1(s##c) __IN2(s,s1,"") : "=a" (_v) : "i" (port) ,##i ); return _v; } \ __IN1(s##_p) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); SLOW_DOWN_IO; return _v; } \ __IN1(s##c_p) __IN2(s,s1,"") : "=a" (_v) : "i" (port) ,##i ); SLOW_DOWN_IO; return _v; } +#define __INS(s) \ +extern inline void ins##s(unsigned short port, void * addr, unsigned long count) \ +{ __asm__ __volatile__ ("cld ; rep ; ins" #s \ +: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); } + +#define __OUTS(s) \ +extern inline void outs##s(unsigned short port, void * addr, unsigned long count) \ +{ __asm__ __volatile__ ("cld ; rep ; outs" #s \ +: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); } + __IN(b,"b","0" (0)) __IN(w,"w","0" (0)) __IN(l,"") @@ -60,6 +70,14 @@ __OUT(b,"b",char) __OUT(w,"w",short) __OUT(l,,int) +__INS(b) +__INS(w) +__INS(l) + +__OUTS(b) +__OUTS(w) +__OUTS(l) + /* * Note that due to the way __builtin_constant_p() works, you * - can't use it inside a inline function (it will never be true) diff --git a/include/linux/fs.h b/include/linux/fs.h index 83e1d82..cac50aa 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -49,6 +49,7 @@ extern unsigned long file_table_init(unsigned long start, unsigned long end); #define MAJOR(a) (int)((unsigned short)(a) >> 8) #define MINOR(a) (int)((unsigned short)(a) & 0xFF) +#define MKDEV(a,b) ((int)((((a) & 0xff) << 8) | ((b) & 0xff))) #ifndef NULL #define NULL ((void *) 0) diff --git a/include/linux/mcd.h b/include/linux/mcd.h index 45b546d..3dedf80 100644 --- a/include/linux/mcd.h +++ b/include/linux/mcd.h @@ -68,7 +68,7 @@ /* borrowed from hd.c */ #define READ_DATA(port, buf, nr) \ -__asm__("cld;rep;insb": :"d" (port),"D" (buf),"c" (nr):"cx","di") +insb(port, buf, nr) #define SET_TIMER(func, jifs) \ ((timer_table[MCD_TIMER].expires = jiffies + jifs), \ diff --git a/include/linux/minix_fs.h b/include/linux/minix_fs.h index ef59ad0..9ddfde7 100644 --- a/include/linux/minix_fs.h +++ b/include/linux/minix_fs.h @@ -22,6 +22,8 @@ #define MINIX_SUPER_MAGIC 0x137F /* original minix fs */ #define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */ #define NEW_MINIX_SUPER_MAGIC 0x2468 /* minix V2 - not implemented */ +#define MINIX_VALID_FS 0x0001 /* Clean fs. */ +#define MINIX_ERROR_FS 0x0002 /* fs has errors. */ #define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode))) @@ -65,6 +67,7 @@ struct minix_super_block { unsigned short s_log_zone_size; unsigned long s_max_size; unsigned short s_magic; + unsigned short s_state; }; struct minix_dir_entry { @@ -100,6 +103,8 @@ extern struct buffer_head * minix_bread(struct inode *, int, int); extern void minix_truncate(struct inode *); extern void minix_put_super(struct super_block *); extern struct super_block *minix_read_super(struct super_block *,void *,int); +extern void minix_write_super(struct super_block *); +extern int minix_remount (struct super_block * sb, int * flags, char * data); extern void minix_read_inode(struct inode *); extern void minix_write_inode(struct inode *); extern void minix_put_inode(struct inode *); diff --git a/include/linux/minix_fs_sb.h b/include/linux/minix_fs_sb.h index c6f0625..a483479 100644 --- a/include/linux/minix_fs_sb.h +++ b/include/linux/minix_fs_sb.h @@ -16,6 +16,9 @@ struct minix_sb_info { struct buffer_head * s_zmap[8]; unsigned long s_dirsize; unsigned long s_namelen; + struct buffer_head * s_sbh; + struct minix_super_block * s_ms; + unsigned short s_mount_state; }; #endif diff --git a/kernel/exit.c b/kernel/exit.c index 0ec3217..41e7742 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -429,7 +429,7 @@ fake_volatile: current->p_cptr = p->p_osptr; p->p_ysptr = NULL; p->flags &= ~(PF_PTRACED|PF_TRACESYS); - if (task[1]) + if (task[1] && task[1] != current) p->p_pptr = task[1]; else p->p_pptr = task[0]; diff --git a/kernel/ksyms.sh b/kernel/ksyms.sh index 4a98ab1..d46f091 100644 --- a/kernel/ksyms.sh +++ b/kernel/ksyms.sh @@ -10,7 +10,7 @@ # # -trap "rm -f ksyms.tmp ksyms.lst" 0 1 2 +trap "rm -f ksyms.tmp ksyms.lst" 1 2 sed -e '/^#/d' -e '/^[ ]*$/d' ksyms.lst | sort > ksyms.tmp @@ -27,7 +27,7 @@ awk 'BEGIN {stringloc = 0} echo ' strings:' awk '{print " .ascii \"" $1 "\\0\""}' ksyms.tmp - +rm -f ksyms.tmp # diff --git a/kernel/sched.c b/kernel/sched.c index 17eca1b..17703c7 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -748,8 +748,10 @@ static void show_task(int nr,struct task_struct * p) printk(stat_nam[p->state]); else printk(" "); - /* this prints bogus values for the current process */ - printk(" %08lX ", ((unsigned long *)p->tss.esp)[2]); + if (p == current) + printk(" current "); + else + printk(" %08lX ", ((unsigned long *)p->tss.esp)[3]); printk("%5lu %5d %6d ", p->tss.esp - p->kernel_stack_page, p->pid, p->p_pptr->pid); if (p->p_cptr) diff --git a/kernel/traps.c b/kernel/traps.c index 03ddea5..776dff0 100644 --- a/kernel/traps.c +++ b/kernel/traps.c @@ -22,6 +22,12 @@ #include <asm/segment.h> #include <asm/io.h> +static inline void console_verbose(void) +{ + extern int console_loglevel; + console_loglevel = 15; +} + #define DO_ERROR(trapnr, signr, str, name, tsk) \ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ { \ @@ -78,6 +84,7 @@ asmlinkage void alignment_check(void); if ((regs->eflags & VM_MASK) || (3 & regs->cs) == 3) return; + console_verbose(); printk("%s: %04lx\n", str, err & 0xffff); printk("EIP: %04x:%08lx\nEFLAGS: %08lx\n", 0xffff & regs->cs,regs->eip,regs->eflags); printk("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n", diff --git a/net/inet/icmp.c b/net/inet/icmp.c index abd1cb5..31049b9 100644 --- a/net/inet/icmp.c +++ b/net/inet/icmp.c @@ -357,7 +357,6 @@ icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt, unsigned long saddr, int redo, struct inet_protocol *protocol) { struct icmphdr *icmph; - unsigned char *buff; /* Drop broadcast packets. */ if (chk_addr(daddr) == IS_BROADCAST) { @@ -368,8 +367,10 @@ icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt, return(0); } - buff = skb1->h.raw; - icmph = (struct icmphdr *) buff; + /* Skip IP-Header */ + len -= skb1->h.iph->ihl << 2; + skb1->h.raw += skb1->h.iph->ihl << 2; + icmph = (struct icmphdr *) skb1->h.raw; /* Validate the packet first */ if (ip_compute_csum((unsigned char *) icmph, len)) { diff --git a/net/inet/ip.c b/net/inet/ip.c index 3a1b1fc..5f76d91 100644 --- a/net/inet/ip.c +++ b/net/inet/ip.c @@ -428,21 +428,22 @@ ip_fast_csum(unsigned char * buff, int wlen) { unsigned long sum = 0; - if (wlen) + if (wlen) { + unsigned long bogus; __asm__("clc\n" "1:\t" "lodsl\n\t" - "adcl %%eax, %0\n\t" + "adcl %3, %0\n\t" "decl %2\n\t" "jne 1b\n\t" "adcl $0, %0\n\t" - "movl %0, %%eax\n\t" - "shrl $16, %%eax\n\t" - "addw %%ax, %w0\n\t" + "movl %0, %3\n\t" + "shrl $16, %3\n\t" + "addw %w3, %w0\n\t" "adcw $0, %w0" - : "=r" (sum), "=S" (buff), "=r" (wlen) - : "0" (sum), "1" (buff), "2" (wlen) - : "ax" ); + : "=r" (sum), "=S" (buff), "=r" (wlen), "=a" (bogus) + : "0" (sum), "1" (buff), "2" (wlen)); + } return (~sum) & 0xffff; } @@ -1266,7 +1267,6 @@ ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) } /* Point into the IP datagram, just past the header. */ - skb->h.raw += iph->ihl*4; hash = iph->protocol & (MAX_INET_PROTOS -1); for (ipprot = (struct inet_protocol *)inet_protos[hash]; ipprot != NULL; @@ -1305,7 +1305,7 @@ ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) * check the protocol handler's return values here... */ ipprot->handler(skb2, dev, opts_p ? &opt : 0, iph->daddr, - (ntohs(iph->tot_len) - (iph->ihl * 4)), + ntohs(iph->tot_len), iph->saddr, 0, ipprot); } diff --git a/net/inet/route.c b/net/inet/route.c index c914c7c..09ab097 100644 --- a/net/inet/route.c +++ b/net/inet/route.c @@ -44,7 +44,7 @@ static struct rtable *rt_base = NULL; - +static struct rtable *rt_loopback = NULL; /* Dump the contents of a routing table entry. */ static void @@ -80,6 +80,8 @@ static void rt_del(unsigned long dst) continue; } *rp = r->rt_next; + if (rt_loopback == r) + rt_loopback = NULL; kfree_s(r, sizeof(struct rtable)); } restore_flags(flags); @@ -105,6 +107,8 @@ void rt_flush(struct device *dev) continue; } *rp = r->rt_next; + if (rt_loopback == r) + rt_loopback = NULL; kfree_s(r, sizeof(struct rtable)); } restore_flags(flags); @@ -216,6 +220,8 @@ rt_add(short flags, unsigned long dst, unsigned long gw, struct device *dev) continue; } *rp = r->rt_next; + if (rt_loopback == r) + rt_loopback = NULL; kfree_s(r, sizeof(struct rtable)); } /* add the new route */ @@ -227,6 +233,8 @@ rt_add(short flags, unsigned long dst, unsigned long gw, struct device *dev) } rt->rt_next = r; *rp = rt; + if (rt->rt_dev->flags & IFF_LOOPBACK) + rt_loopback = rt; restore_flags(cpuflags); return; } @@ -306,41 +314,28 @@ rt_get_info(char *buffer) return(pos - buffer); } - /* - * rewrote this too.. Maybe somebody can understand it now. Linus + * This is hackish, but results in better code. Use "-S" to see why. */ +#define early_out ({ goto no_route; 1; }) + struct rtable * rt_route(unsigned long daddr, struct options *opt) { struct rtable *rt; - int type; - /* - * This is a hack, I think. -FvK - */ - if ((type=chk_addr(daddr)) == IS_MYADDR) daddr = my_addr(); - - /* - * Loop over the IP routing table to find a route suitable - * for this packet. Note that we really should have a look - * at the IP options to see if we have been given a hint as - * to what kind of path we should use... -FvK - */ - /* - * This depends on 'rt_mask' and the ordering set up in 'rt_add()' - Linus - */ - for (rt = rt_base; rt != NULL; rt = rt->rt_next) { - if (!((rt->rt_dst ^ daddr) & rt->rt_mask)) { - rt->rt_use++; - return rt; - } + for (rt = rt_base; rt != NULL || early_out ; rt = rt->rt_next) { + if (!((rt->rt_dst ^ daddr) & rt->rt_mask)) + break; /* broadcast addresses can be special cases.. */ if ((rt->rt_dev->flags & IFF_BROADCAST) && - rt->rt_dev->pa_brdaddr == daddr) { - rt->rt_use++; - return(rt); - } + rt->rt_dev->pa_brdaddr == daddr) + break; } + if (daddr == rt->rt_dev->pa_addr) + rt = rt_loopback; + rt->rt_use++; + return rt; +no_route: return NULL; } diff --git a/net/inet/tcp.c b/net/inet/tcp.c index 83dfb41..c3be0bc 100644 --- a/net/inet/tcp.c +++ b/net/inet/tcp.c @@ -2934,6 +2934,9 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, DPRINTF((DBG_TCP, "tcp.c: tcp_rcv dev = NULL\n")); return(0); } + /* Skip IP-Header */ + len -= skb->h.iph->ihl << 2; + skb->h.raw += skb->h.iph->ihl << 2; th = skb->h.th; /* Find the socket. */ diff --git a/net/inet/udp.c b/net/inet/udp.c index 78066c3..74e0a2e 100644 --- a/net/inet/udp.c +++ b/net/inet/udp.c @@ -550,6 +550,9 @@ udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, struct sock *sk; struct udphdr *uh; + /* Skip IP-Header */ + len -= skb->h.iph->ihl << 2; + skb->h.raw += skb->h.iph->ihl << 2; uh = (struct udphdr *) skb->h.uh; sk = get_sock(&udp_prot, uh->dest, saddr, uh->source, daddr); if (sk == NULL) diff --git a/net/socket.c b/net/socket.c index 6885fe7..e679128 100644 --- a/net/socket.c +++ b/net/socket.c @@ -231,6 +231,7 @@ static void sock_release(struct socket *sock) { int oldstate; + struct inode *inode; struct socket *peersock, *nextsock; DPRINTF((net_debug, "NET: sock_release: socket 0x%x, inode 0x%x\n", @@ -251,11 +252,12 @@ sock_release(struct socket *sock) peersock = (oldstate == SS_CONNECTED) ? sock->conn : NULL; if (sock->ops) sock->ops->release(sock, peersock); if (peersock) sock_release_peer(peersock); + inode = SOCK_INODE(sock); sock->state = SS_FREE; /* this really releases us */ wake_up(&socket_wait_free); /* We need to do this. If sock alloc was called we already have an inode. */ - iput(SOCK_INODE(sock)); + iput(inode); } diff --git a/net/unix/proc.c b/net/unix/proc.c index 68bd106..8a80ad5 100644 --- a/net/unix/proc.c +++ b/net/unix/proc.c @@ -16,7 +16,6 @@ * Fred Baumgarten, <dc6iq@insu1.etec.uni-kalrsruhe.de> * * Fixes: - * Andriews Brouwer : Comment errors * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License |