diff -ru --new-file 2.3.40.clean/Documentation/Configure.help 2.3.40/Documentation/Configure.help --- 2.3.40.clean/Documentation/Configure.help Sun Jan 23 05:30:47 2000 +++ 2.3.40/Documentation/Configure.help Sun Jan 23 01:07:10 2000 @@ -7513,14 +7513,16 @@ Linux Token Ring Project site for the latest information at http://www.linuxtr.net -Generic TMS380 Token Ring ISA/PCI adapter support +Generic TMS380 Token Ring ISA/PCI/MCA/EISA adapter support CONFIG_TMS380TR This driver provides generic support for token ring adapters based on the Texas Instruments TMS380 series chipsets. This includes the SysKonnect TR4/16(+) ISA (SK-4190), SysKonnect TR4/16(+) PCI (SK-4590), SysKonnect TR4/16 PCI (SK-4591), - Compaq 4/16 PCI, Thomas-Conrad TC4048 4/16 PCI, and Intel - TokenExpress 4/16 and PRO ISA adapters. + Compaq 4/16 PCI, Thomas-Conrad TC4048 4/16 PCI, and several + Madge adapters. If selected, you will be asked to select + which cards to support below. If you're using modules, each + class of card will be supported by a seperate module. If you have such an adapter and would like to use it, say Y or M and read the Token-Ring mini-HOWTO, available from @@ -7528,6 +7530,25 @@ Also read the file linux/Documentation/networking/tms380tr.txt or check http://www.auk.cx/tms380tr/ + +Generic TMS380 PCI support +CONFIG_TMSPCI + This tms380 module supports generic TMS380-based PCI cards. + + These cards are known to work: + - Compaq 4/16 TR PCI + - SysKonnect TR4/16 PCI (SK-4590/SK-4591) + - Thomas-Conrad TC4048 PCI 4/16 + - 3Com Token Link Velocity + +Madge Smart 16/4 PCI Mk2 support +CONFIG_ABYSS + This tms380 module supports the Madge Smart 16/4 PCI Mk2 cards (51-02). + +Madge Smart 16/4 Ringode MicroChannel +CONFIG_MADGEMC + This tms380 module supports the Madge Smart 16/4 MC16 and MC32 + MicroChannel adapters SMC ISA TokenRing adapter support CONFIG_SMCTR diff -ru --new-file 2.3.40.clean/Makefile 2.3.40/Makefile --- 2.3.40.clean/Makefile Sun Jan 23 05:30:47 2000 +++ 2.3.40/Makefile Sun Jan 23 01:07:11 2000 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 3 SUBLEVEL = 41 -EXTRAVERSION = +EXTRAVERSION = mid1 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) diff -ru --new-file 2.3.40.clean/arch/i386/kernel/mca.c 2.3.40/arch/i386/kernel/mca.c --- 2.3.40.clean/arch/i386/kernel/mca.c Sat Nov 20 05:16:10 1999 +++ 2.3.40/arch/i386/kernel/mca.c Sun Jan 23 01:07:11 2000 @@ -274,11 +274,15 @@ * read its POS registers. Then put adapter setup off. */ + printk("MCA Bus Devices:\n"); for(i=0; islot[i].pos[j]=inb_p(MCA_POS_REG(j)); + printk("%02x ", mca_info->slot[i].pos[j]); } + printk("\n"); mca_info->slot[i].name[0] = 0; mca_info->slot[i].driver_loaded = 0; mca_configure_adapter_status(i); diff -ru --new-file 2.3.40.clean/drivers/net/Space.c 2.3.40/drivers/net/Space.c --- 2.3.40.clean/drivers/net/Space.c Thu Jan 6 23:01:56 2000 +++ 2.3.40/drivers/net/Space.c Sun Jan 23 01:07:11 2000 @@ -569,7 +569,6 @@ /* Token-ring device probe */ extern int ibmtr_probe(struct net_device *); extern int olympic_probe(struct net_device *); -extern int tms380tr_probe(struct net_device *); extern int smctr_probe(struct net_device *); static int @@ -581,9 +580,6 @@ #endif #ifdef CONFIG_IBMOL && olympic_probe(dev) -#endif -#ifdef CONFIG_SKTR - && tms380tr_probe(dev) #endif #ifdef CONFIG_SMCTR && smctr_probe(dev) diff -ru --new-file 2.3.40.clean/drivers/net/eexpress.c 2.3.40/drivers/net/eexpress.c --- 2.3.40.clean/drivers/net/eexpress.c Wed Sep 8 18:51:22 1999 +++ 2.3.40/drivers/net/eexpress.c Sun Jan 23 01:07:11 2000 @@ -9,6 +9,7 @@ * Many modifications, and currently maintained, by * Philip Blundell * Added the Compaq LTE Alan Cox + * Added MCA support Adam Fritzler * * Note - this driver is experimental still - it has problems on faster * machines. Someone needs to sit down and go through it line by line with @@ -121,6 +122,10 @@ #include #include +#ifdef CONFIG_MCA +#include +#endif + #include #ifndef NET_DEBUG @@ -232,6 +237,16 @@ /* maps irq number to EtherExpress magic value */ static char irqrmap[] = { 0,0,1,2,3,4,0,0,0,1,5,6,0,0,0,0 }; +#ifdef CONFIG_MCA +/* mapping of the first four bits of the second POS register */ +static unsigned short mca_iomap[] = { + 0x270, 0x260, 0x250, 0x240, 0x230, 0x220, 0x210, 0x200, + 0x370, 0x360, 0x350, 0x340, 0x330, 0x320, 0x310, 0x300 +}; +/* bits 5-7 of the second POS register */ +static char mca_irqmap[] = { 12, 9, 3, 4, 5, 10, 11, 15 }; +#endif + /* * Prototypes for Linux interface */ @@ -331,6 +346,55 @@ static unsigned short ports[] = { 0x300,0x310,0x270,0x320,0x340,0 }; unsigned short ioaddr = dev->base_addr; + dev->if_port = 0xff; /* not set */ + +#ifdef CONFIG_MCA + if (MCA_bus) { + int slot = 0; + + /* + * Only find one card at a time. Subsequent calls + * will find others, however, proper multicard MCA + * probing and setup can't be done with the + * old-style Space.c init routines. -- ASF + */ + while (slot != MCA_NOTFOUND) { + int pos0, pos1; + + slot = mca_find_unused_adapter(0x628B, slot); + if (slot == MCA_NOTFOUND) + break; + + pos0 = mca_read_stored_pos(slot, 2); + pos1 = mca_read_stored_pos(slot, 3); + ioaddr = mca_iomap[pos1&0xf]; + + dev->irq = mca_irqmap[(pos1>>4)&0x7]; + + /* + * XXX: Transciever selection is done + * differently on the MCA version. + * How to get it to select something + * other than external/AUI is currently + * unknown. This code is just for looks. -- ASF + */ + if ((pos0 & 0x7) == 0x1) + dev->if_port = AUI; + else if ((pos0 & 0x7) == 0x5) { + if (pos1 & 0x80) + dev->if_port = BNC; + else + dev->if_port = TPE; + } + + mca_set_adapter_name(slot, "Intel EtherExpress 16 MCA"); + mca_set_adapter_procfn(slot, NULL, dev); + mca_mark_as_used(slot); + + break; + } + } +#endif if (ioaddr&0xfe00) return eexp_hw_probe(dev,ioaddr); else if (ioaddr) @@ -522,7 +586,9 @@ static int eexp_xmit(struct sk_buff *buf, struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; +#ifdef CONFIG_SMP unsigned long flags; +#endif #if NET_DEBUG > 6 printk(KERN_DEBUG "%s: eexp_xmit()\n", dev->name); @@ -1010,8 +1076,10 @@ if (!dev->irq) dev->irq = irqmap[setupval>>13]; - dev->if_port = !(setupval & 0x1000) ? AUI : - eexp_hw_readeeprom(ioaddr,5) & 0x1 ? TPE : BNC; + if (dev->if_port == 0xff) { + dev->if_port = !(setupval & 0x1000) ? AUI : + eexp_hw_readeeprom(ioaddr,5) & 0x1 ? TPE : BNC; + } buswidth = !((setupval & 0x400) >> 10); } diff -ru --new-file 2.3.40.clean/drivers/net/setup.c 2.3.40/drivers/net/setup.c --- 2.3.40.clean/drivers/net/setup.c Sun Jan 23 05:30:50 2000 +++ 2.3.40/drivers/net/setup.c Sun Jan 23 01:07:11 2000 @@ -58,6 +58,10 @@ extern int via_rhine_probe(void); extern int yellowfin_probe(void); +extern int abyss_probe(void); +extern int madgemc_probe(void); +extern int tms_pci_probe(void); + /* Pad device name to IFNAMSIZ=16. F.e. __PAD6 is tring of 9 zeros. */ #define __PAD6 "\0\0\0\0\0\0\0\0\0" #define __PAD5 __PAD6 "\0" @@ -250,7 +254,19 @@ #ifdef CONFIG_YAM {yam_init, 0}, #endif /* CONFIG_YAM */ - + +/* + * Token Ring Drivers + */ +#ifdef CONFIG_ABYSS + {abyss_probe, 0}, +#endif +#ifdef CONFIG_MADGEMC + {madgemc_probe, 0}, +#endif +#ifdef CONFIG_TMSPCI + {tms_pci_probe, 0}, +#endif {NULL, 0}, }; diff -ru --new-file 2.3.40.clean/drivers/net/tokenring/Config.in 2.3.40/drivers/net/tokenring/Config.in --- 2.3.40.clean/drivers/net/tokenring/Config.in Thu Jan 6 23:01:56 2000 +++ 2.3.40/drivers/net/tokenring/Config.in Sun Jan 23 01:07:11 2000 @@ -6,11 +6,16 @@ comment 'Token Ring driver support' bool 'Token Ring driver support' CONFIG_TR -if [ "$CONFIG_TR" = "y" ]; then - tristate ' IBM Tropic chipset based adapter support' CONFIG_IBMTR - tristate ' IBM Olympic chipset PCI adapter support' CONFIG_IBMOL - tristate ' Generic TMS380 Token Ring ISA/PCI adapter support' CONFIG_TMS380TR - tristate ' SMC ISA adapter support' CONFIG_SMCTR +if [ "$CONFIG_TR" != "n" ]; then + dep_tristate ' IBM Tropic chipset based adapter support' CONFIG_IBMTR $CONFIG_TR + dep_tristate ' IBM Olympic chipset PCI adapter support' CONFIG_IBMOL $CONFIG_TR + dep_tristate ' Generic TMS380 Token Ring ISA/PCI adapter support' CONFIG_TMS380TR $CONFIG_TR + if [ "$CONFIG_TMS380TR" != "n" ]; then + dep_tristate ' Generic TMS380 PCI support' CONFIG_TMSPCI $CONFIG_TMS380TR + dep_tristate ' Madge Smart 16/4 PCI Mk2 support' CONFIG_ABYSS $CONFIG_TMS380TR + dep_tristate ' Madge Smart 16/4 Ringnode MicroChannel' CONFIG_MADGEMC $CONFIG_TMS380TR + fi + dep_tristate ' SMC ISA adapter support' CONFIG_SMCTR $CONFIG_TR fi endmenu diff -ru --new-file 2.3.40.clean/drivers/net/tokenring/Makefile 2.3.40/drivers/net/tokenring/Makefile --- 2.3.40.clean/drivers/net/tokenring/Makefile Thu Jan 6 23:01:56 2000 +++ 2.3.40/drivers/net/tokenring/Makefile Sun Jan 23 01:07:11 2000 @@ -41,9 +41,27 @@ ifeq ($(CONFIG_TMS380TR),y) L_OBJS += tms380tr.o + ifeq ($(CONFIG_ABYSS),y) + L_OBJS += abyss.o + endif + ifeq ($(CONFIG_MADGEMC),y) + L_OBJS += madgemc.o + endif + ifeq ($(CONFIG_TMSPCI),y) + L_OBJS += tmspci.o + endif else ifeq ($(CONFIG_TMS380TR),m) M_OBJS += tms380tr.o + ifeq ($(CONFIG_ABYSS),m) + M_OBJS += abyss.o + endif + ifeq ($(CONFIG_MADGEMC),m) + M_OBJS += madgemc.o + endif + ifeq ($(CONFIG_TMSPCI),m) + M_OBJS += tmspci.o + endif endif endif diff -ru --new-file 2.3.40.clean/drivers/net/tokenring/abyss.c 2.3.40/drivers/net/tokenring/abyss.c --- 2.3.40.clean/drivers/net/tokenring/abyss.c Thu Jan 1 00:00:00 1970 +++ 2.3.40/drivers/net/tokenring/abyss.c Sun Jan 23 05:10:52 2000 @@ -0,0 +1,512 @@ +/* + * abyss.c: Network driver for the Madge Smart 16/4 PCI Mk2 token ring card. + * + * Written 1999-2000 by Adam Fritzler + * + * This software may be used and distributed according to the terms + * of the GNU Public License, incorporated herein by reference. + * + * This driver module supports the following cards: + * - Madge Smart 16/4 PCI Mk2 + * + * Maintainer(s): + * AF Adam Fritzler mid@auk.cx + * + * Modification History: + * 30-Dec-99 AF Split off from the tms380tr driver. + * 22-Jan-00 AF Updated to use indirect read/writes + * + * + * TODO: + * 1. See if we can use MMIO instead of inb/outb/inw/outw + * 2. Add support for Mk1 (has AT24 attached to the PCI + * config registers) + * + */ +static const char *version = "abyss.c: v1.01 22/01/2000 by Adam Fritzler\n"; + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include "tms380tr.h" +#include "abyss.h" /* Madge-specific constants */ + +#define ABYSS_IO_EXTENT 64 + +int abyss_probe(void); +static int abyss_open(struct net_device *dev); +static int abyss_close(struct net_device *dev); +static void abyss_enable(struct net_device *dev); +static int abyss_chipset_init(struct net_device *dev); +static void abyss_read_eeprom(struct net_device *dev); +static unsigned short abyss_setnselout_pins(struct net_device *dev); + +void at24_writedatabyte(unsigned long regaddr, unsigned char byte); +int at24_sendfullcmd(unsigned long regaddr, unsigned char cmd, unsigned char addr); +int at24_sendcmd(unsigned long regaddr, unsigned char cmd); +unsigned char at24_readdatabit(unsigned long regaddr); +unsigned char at24_readdatabyte(unsigned long regaddr); +int at24_waitforack(unsigned long regaddr); +int at24_waitfornack(unsigned long regaddr); +void at24_setlines(unsigned long regaddr, unsigned char clock, unsigned char data); +void at24_start(unsigned long regaddr); +void at24_stop(unsigned long regaddr); +unsigned char at24_readb(unsigned long regaddr, unsigned char addr); + +static unsigned short abyss_sifreadb(struct net_device *dev, unsigned short reg) +{ + return inb(dev->base_addr + reg); +} + +static unsigned short abyss_sifreadw(struct net_device *dev, unsigned short reg) +{ + return inw(dev->base_addr + reg); +} + +static void abyss_sifwriteb(struct net_device *dev, unsigned short val, unsigned short reg) +{ + outb(val, dev->base_addr + reg); +} + +static void abyss_sifwritew(struct net_device *dev, unsigned short val, unsigned short reg) +{ + outw(val, dev->base_addr + reg); +} + +struct tms_abyss_card { + struct net_device *dev; + struct pci_dev *pci_dev; + struct tms_abyss_card *next; +}; +static struct tms_abyss_card *abyss_card_list = NULL; + +int __init abyss_probe(void) +{ + static int versionprinted = 0; + struct pci_dev *pdev = NULL ; + struct net_device *dev; + struct net_local *tp; + int i; + + if (!pci_present()) + return (-1); /* No PCI present. */ + + while ( (pdev=pci_find_class(PCI_CLASS_NETWORK_TOKEN_RING<<8, pdev))) { + unsigned int pci_irq_line; + unsigned long pci_ioaddr; + struct tms_abyss_card *card; + + /* We only support Madge Smart 16/4 PCI Mk2 (Abyss) cards */ + if ( (pdev->vendor != PCI_VENDOR_ID_MADGE) || + (pdev->device != PCI_DEVICE_ID_MADGE_MK2) ) + continue; + + if (versionprinted++ == 0) + printk("%s", version); + + pci_enable_device(pdev); + + /* Remove I/O space marker in bit 0. */ + pci_irq_line = pdev->irq; + pci_ioaddr = pdev->resource[0].start ; + + if(check_region(pci_ioaddr, ABYSS_IO_EXTENT)) + continue; + + /* At this point we have found a valid card. */ + + dev = init_trdev(NULL, 0); + + request_region(pci_ioaddr, ABYSS_IO_EXTENT, "abyss"); + if(request_irq(pdev->irq, tms380tr_interrupt, SA_SHIRQ, + "abyss", dev)) { + release_region(pci_ioaddr, ABYSS_IO_EXTENT) ; + continue; /*return (-ENODEV);*/ /* continue; ?? */ + } + + /* + if (load_tms380_module("abyss.c")) { + return 0; + } + */ + + pci_ioaddr &= ~3 ; + dev->base_addr = pci_ioaddr; + dev->irq = pci_irq_line; + dev->dma = 0; + + printk("%s: Madge Smart 16/4 PCI Mk2 (Abyss)\n", dev->name); + printk("%s: IO: %#4lx IRQ: %d\n", + dev->name, pci_ioaddr, dev->irq); + /* + * The TMS SIF registers lay 0x10 above the card base address. + */ + dev->base_addr += 0x10; + + if (tmsdev_init(dev)) { + printk("%s: unable to get memory for dev->priv.\n", + dev->name); + return 0; + } + + abyss_read_eeprom(dev); + + printk("%s: Ring Station Address: ", dev->name); + printk("%2.2x", dev->dev_addr[0]); + for (i = 1; i < 6; i++) + printk(":%2.2x", dev->dev_addr[i]); + printk("\n"); + + tp = (struct net_local *)dev->priv; + tp->dmalimit = 0; /* XXX: should be the max PCI32 DMA max */ + tp->setnselout = abyss_setnselout_pins; + tp->sifreadb = abyss_sifreadb; + tp->sifreadw = abyss_sifreadw; + tp->sifwriteb = abyss_sifwriteb; + tp->sifwritew = abyss_sifwritew; + + memcpy(tp->ProductID, "Madge PCI 16/4 Mk2", PROD_ID_SIZE + 1); + + dev->open = abyss_open; + dev->stop = abyss_close; + + if (register_trdev(dev) == 0) { + /* Enlist in the card list */ + card = kmalloc(sizeof(struct tms_abyss_card), + GFP_KERNEL); + card->next = abyss_card_list; + abyss_card_list = card; + card->dev = dev; + card->pci_dev = pdev; + } else { + printk("abyss: register_trdev() returned non-zero.\n"); + kfree(dev->priv); + kfree(dev); + return -1; + } + } + + if (abyss_card_list) + return 0; + return (-1); +} + +unsigned short abyss_setnselout_pins(struct net_device *dev) +{ + unsigned short val = 0; + struct net_local *tp = (struct net_local *)dev->priv; + + if(tp->DataRate == SPEED_4) + val |= 0x01; /* Set 4Mbps */ + else + val |= 0x00; /* Set 16Mbps */ + + return val; +} + +/* + * The following Madge boards should use this code: + * - Smart 16/4 PCI Mk2 (Abyss) + * - Smart 16/4 PCI Mk1 (PCI T) + * - Smart 16/4 Client Plus PnP (Big Apple) + * - Smart 16/4 Cardbus Mk2 + * + * These access an Atmel AT24 SEEPROM using their glue chip registers. + * + */ +void at24_writedatabyte(unsigned long regaddr, unsigned char byte) +{ + int i; + + for (i = 0; i < 8; i++) { + at24_setlines(regaddr, 0, (byte >> (7-i))&0x01); + at24_setlines(regaddr, 1, (byte >> (7-i))&0x01); + at24_setlines(regaddr, 0, (byte >> (7-i))&0x01); + } +} + +int at24_sendfullcmd(unsigned long regaddr, unsigned char cmd, unsigned char addr) +{ + if (at24_sendcmd(regaddr, cmd)) { + at24_writedatabyte(regaddr, addr); + return at24_waitforack(regaddr); + } + return 0; +} + +int at24_sendcmd(unsigned long regaddr, unsigned char cmd) +{ + int i; + + for (i = 0; i < 10; i++) { + at24_start(regaddr); + at24_writedatabyte(regaddr, cmd); + if (at24_waitforack(regaddr)) + return 1; + } + return 0; +} + +unsigned char at24_readdatabit(unsigned long regaddr) +{ + unsigned char val; + + at24_setlines(regaddr, 0, 1); + at24_setlines(regaddr, 1, 1); + val = (inb(regaddr) & AT24_DATA)?1:0; + at24_setlines(regaddr, 1, 1); + at24_setlines(regaddr, 0, 1); + return val; +} + +unsigned char at24_readdatabyte(unsigned long regaddr) +{ + unsigned char data = 0; + int i; + + for (i = 0; i < 8; i++) { + data <<= 1; + data |= at24_readdatabit(regaddr); + } + + return data; +} + +int at24_waitforack(unsigned long regaddr) +{ + int i; + + for (i = 0; i < 10; i++) { + if ((at24_readdatabit(regaddr) & 0x01) == 0x00) + return 1; + } + return 0; +} + +int at24_waitfornack(unsigned long regaddr) +{ + int i; + for (i = 0; i < 10; i++) { + if ((at24_readdatabit(regaddr) & 0x01) == 0x01) + return 1; + } + return 0; +} + +void at24_setlines(unsigned long regaddr, unsigned char clock, unsigned char data) +{ + unsigned char val; + val = AT24_ENABLE; + if (clock) + val |= AT24_CLOCK; + if (data) + val |= AT24_DATA; + + outb(val, regaddr); + tms380tr_wait(20); /* Very necessary. */ +} + +void at24_start(unsigned long regaddr) +{ + at24_setlines(regaddr, 0, 1); + at24_setlines(regaddr, 1, 1); + at24_setlines(regaddr, 1, 0); + at24_setlines(regaddr, 0, 1); + return; +} + +void at24_stop(unsigned long regaddr) +{ + at24_setlines(regaddr, 0, 0); + at24_setlines(regaddr, 1, 0); + at24_setlines(regaddr, 1, 1); + at24_setlines(regaddr, 0, 1); + return; +} + +unsigned char at24_readb(unsigned long regaddr, unsigned char addr) +{ + unsigned char data = 0xff; + + if (at24_sendfullcmd(regaddr, AT24_WRITE, addr)) { + if (at24_sendcmd(regaddr, AT24_READ)) { + data = at24_readdatabyte(regaddr); + if (!at24_waitfornack(regaddr)) + data = 0xff; + } + } + return data; +} + + +/* + * Enable basic functions of the Madge chipset needed + * for initialization. + */ +static void abyss_enable(struct net_device *dev) +{ + unsigned char reset_reg; + unsigned long ioaddr; + + ioaddr = dev->base_addr; + reset_reg = inb(ioaddr + PCIBM2_RESET_REG); + reset_reg |= PCIBM2_RESET_REG_CHIP_NRES; + outb(reset_reg, ioaddr + PCIBM2_RESET_REG); + tms380tr_wait(100); + return; +} + +/* + * Enable the functions of the Madge chipset needed for + * full working order. + */ +static int abyss_chipset_init(struct net_device *dev) +{ + unsigned char reset_reg; + unsigned long ioaddr; + + ioaddr = dev->base_addr; + + reset_reg = inb(ioaddr + PCIBM2_RESET_REG); + + reset_reg |= PCIBM2_RESET_REG_CHIP_NRES; + outb(reset_reg, ioaddr + PCIBM2_RESET_REG); + + reset_reg &= ~(PCIBM2_RESET_REG_CHIP_NRES | + PCIBM2_RESET_REG_FIFO_NRES | + PCIBM2_RESET_REG_SIF_NRES); + outb(reset_reg, ioaddr + PCIBM2_RESET_REG); + + tms380tr_wait(100); + + reset_reg |= PCIBM2_RESET_REG_CHIP_NRES; + outb(reset_reg, ioaddr + PCIBM2_RESET_REG); + + reset_reg |= PCIBM2_RESET_REG_SIF_NRES; + outb(reset_reg, ioaddr + PCIBM2_RESET_REG); + + reset_reg |= PCIBM2_RESET_REG_FIFO_NRES; + outb(reset_reg, ioaddr + PCIBM2_RESET_REG); + + outb(PCIBM2_INT_CONTROL_REG_SINTEN | + PCIBM2_INT_CONTROL_REG_PCI_ERR_ENABLE, + ioaddr + PCIBM2_INT_CONTROL_REG); + + outb(30, ioaddr + PCIBM2_FIFO_THRESHOLD); + + return 0; +} + +void abyss_chipset_close(struct net_device *dev) +{ + unsigned long ioaddr; + + ioaddr = dev->base_addr; + outb(0, ioaddr + PCIBM2_RESET_REG); + + return; +} + +/* + * Read configuration data from the AT24 SEEPROM on Madge cards. + * + */ +static void abyss_read_eeprom(struct net_device *dev) +{ + struct net_local *tp; + unsigned long ioaddr; + unsigned short val; + int i; + + tp = (struct net_local *)dev->priv; + ioaddr = dev->base_addr; + + /* Must enable glue chip first */ + abyss_enable(dev); + + val = at24_readb(ioaddr + PCIBM2_SEEPROM_REG, + PCIBM2_SEEPROM_RING_SPEED); + tp->DataRate = val?SPEED_4:SPEED_16; /* set open speed */ + printk("%s: SEEPROM: ring speed: %dMb/sec\n", dev->name, tp->DataRate); + + val = at24_readb(ioaddr + PCIBM2_SEEPROM_REG, + PCIBM2_SEEPROM_RAM_SIZE) * 128; + printk("%s: SEEPROM: adapter RAM: %dkb\n", dev->name, val); + + dev->addr_len = 6; + for (i = 0; i < 6; i++) + dev->dev_addr[i] = at24_readb(ioaddr + PCIBM2_SEEPROM_REG, + PCIBM2_SEEPROM_BIA+i); + + return; +} + +static int abyss_open(struct net_device *dev) +{ + abyss_chipset_init(dev); + tms380tr_open(dev); + MOD_INC_USE_COUNT; + return 0; +} + +static int abyss_close(struct net_device *dev) +{ + tms380tr_close(dev); + abyss_chipset_close(dev); + MOD_DEC_USE_COUNT; + return 0; +} + +#ifdef MODULE + +int init_module(void) +{ + /* Probe for cards. */ + if (abyss_probe()) { + printk(KERN_NOTICE "abyss.c: No cards found.\n"); + } + /* lock_tms380_module(); */ + return (0); +} + +void cleanup_module(void) +{ + struct net_device *dev; + struct tms_abyss_card *this_card; + + while (abyss_card_list) { + dev = abyss_card_list->dev; + unregister_netdev(dev); + release_region(dev->base_addr-0x10, ABYSS_IO_EXTENT); + free_irq(dev->irq, dev); + kfree(dev->priv); + kfree(dev); + this_card = abyss_card_list; + abyss_card_list = this_card->next; + kfree(this_card); + } + /* unlock_tms380_module(); */ +} +#endif /* MODULE */ + + +/* + * Local variables: + * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c abyss.c" + * alt-compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c abyss.c" + * c-set-style "K&R" + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff -ru --new-file 2.3.40.clean/drivers/net/tokenring/abyss.h 2.3.40/drivers/net/tokenring/abyss.h --- 2.3.40.clean/drivers/net/tokenring/abyss.h Thu Jan 1 00:00:00 1970 +++ 2.3.40/drivers/net/tokenring/abyss.h Sun Jan 23 01:07:11 2000 @@ -0,0 +1,58 @@ +/* + * abyss.h: Header for the abyss tms380tr module + * + * Authors: + * - Adam Fritzler + */ + +#ifndef __LINUX_MADGETR_H +#define __LINUX_MADGETR_H + +#ifdef __KERNEL__ + +/* + * For Madge Smart 16/4 PCI Mk2. Since we increment the base address + * to get everything correct for the TMS SIF, we do these as negatives + * as they fall below the SIF in addressing. + */ +#define PCIBM2_INT_STATUS_REG ((short)-15)/* 0x01 */ +#define PCIBM2_INT_CONTROL_REG ((short)-14)/* 0x02 */ +#define PCIBM2_RESET_REG ((short)-12)/* 0x04 */ +#define PCIBM2_SEEPROM_REG ((short)-9) /* 0x07 */ + +#define PCIBM2_INT_CONTROL_REG_SINTEN 0x02 +#define PCIBM2_INT_CONTROL_REG_PCI_ERR_ENABLE 0x80 +#define PCIBM2_INT_STATUS_REG_PCI_ERR 0x80 + +#define PCIBM2_RESET_REG_CHIP_NRES 0x01 +#define PCIBM2_RESET_REG_FIFO_NRES 0x02 +#define PCIBM2_RESET_REG_SIF_NRES 0x04 + +#define PCIBM2_FIFO_THRESHOLD 0x21 +#define PCIBM2_BURST_LENGTH 0x22 + +/* + * Bits in PCIBM2_SEEPROM_REG. + */ +#define AT24_ENABLE 0x04 +#define AT24_DATA 0x02 +#define AT24_CLOCK 0x01 + +/* + * AT24 Commands. + */ +#define AT24_WRITE 0xA0 +#define AT24_READ 0xA1 + +/* + * Addresses in AT24 SEEPROM. + */ +#define PCIBM2_SEEPROM_BIA 0x12 +#define PCIBM2_SEEPROM_RING_SPEED 0x18 +#define PCIBM2_SEEPROM_RAM_SIZE 0x1A +#define PCIBM2_SEEPROM_HWF1 0x1C +#define PCIBM2_SEEPROM_HWF2 0x1E + + +#endif /* __KERNEL__ */ +#endif /* __LINUX_MADGETR_H */ diff -ru --new-file 2.3.40.clean/drivers/net/tokenring/madgemc.c 2.3.40/drivers/net/tokenring/madgemc.c --- 2.3.40.clean/drivers/net/tokenring/madgemc.c Thu Jan 1 00:00:00 1970 +++ 2.3.40/drivers/net/tokenring/madgemc.c Sun Jan 23 05:21:10 2000 @@ -0,0 +1,806 @@ +/* + * madgemc.c: Driver for the Madge Smart 16/4 MC16 MCA token ring card. + * + * Written 2000 by Adam Fritzler + * + * This software may be used and distributed according to the terms + * of the GNU Public License, incorporated herein by reference. + * + * This driver module supports the following cards: + * - Madge Smart 16/4 Ringnode MC16 + * - Madge Smart 16/4 Ringnode MC32 (??) + * + * Maintainer(s): + * AF Adam Fritzler mid@auk.cx + * + * Modification History: + * 16-Jan-00 AF Created + * + */ +static const char *version = "madgemc.c: v0.91 23/01/2000 by Adam Fritzler\n"; + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include "tms380tr.h" +#include "madgemc.h" /* Madge-specific constants */ + +#define MADGEMC_IO_EXTENT 32 +#define MADGEMC_SIF_OFFSET 0x08 + +struct madgemc_card { + struct net_device *dev; + + /* + * These are read from the BIA ROM. + */ + unsigned int manid; + unsigned int cardtype; + unsigned int cardrev; + unsigned int ramsize; + + /* + * These are read from the MCA POS registers. + */ + unsigned int burstmode:2; + unsigned int fairness:1; /* 0 = Fair, 1 = Unfair */ + unsigned int arblevel:4; + unsigned int ringspeed:2; /* 0 = 4mb, 1 = 16, 2 = Auto/none */ + unsigned int cabletype:1; /* 0 = RJ45, 1 = DB9 */ + + struct madgemc_card *next; +}; +static struct madgemc_card *madgemc_card_list = NULL; + + +int madgemc_probe(void); +static int madgemc_open(struct net_device *dev); +static int madgemc_close(struct net_device *dev); +static int madgemc_chipset_init(struct net_device *dev); +static void madgemc_read_rom(struct madgemc_card *card); +static unsigned short madgemc_setnselout_pins(struct net_device *dev); +static void madgemc_setcabletype(struct net_device *dev, int type); + +static int madgemc_mcaproc(char *buf, int slot, void *d); + +static void madgemc_setregpage(struct net_device *dev, int page); +static void madgemc_setsifsel(struct net_device *dev, int val); +static void madgemc_setint(struct net_device *dev, int val); + +static void madgemc_interrupt(int irq, void *dev_id, struct pt_regs *regs); + +/* + * These work around paging, however they dont guarentee you're on the + * right page. + */ +#define SIFREADB(reg) (inb(dev->base_addr + ((reg<0x8)?reg:reg-0x8))) +#define SIFWRITEB(val, reg) (outb(val, dev->base_addr + ((reg<0x8)?reg:reg-0x8))) +#define SIFREADW(reg) (inw(dev->base_addr + ((reg<0x8)?reg:reg-0x8))) +#define SIFWRITEW(val, reg) (outw(val, dev->base_addr + ((reg<0x8)?reg:reg-0x8))) + +/* + * Read a byte-length value from the register. + */ +static unsigned short madgemc_sifreadb(struct net_device *dev, unsigned short reg) +{ + unsigned short ret; + if (reg<0x8) + ret = SIFREADB(reg); + else { + madgemc_setregpage(dev, 1); + ret = SIFREADB(reg); + madgemc_setregpage(dev, 0); + } + return ret; +} + +/* + * Write a byte-length value to a register. + */ +static void madgemc_sifwriteb(struct net_device *dev, unsigned short val, unsigned short reg) +{ + if (reg<0x8) + SIFWRITEB(val, reg); + else { + madgemc_setregpage(dev, 1); + SIFWRITEB(val, reg); + madgemc_setregpage(dev, 0); + } + return; +} + +/* + * Read a word-length value from a register + */ +static unsigned short madgemc_sifreadw(struct net_device *dev, unsigned short reg) +{ + unsigned short ret; + if (reg<0x8) + ret = SIFREADW(reg); + else { + madgemc_setregpage(dev, 1); + ret = SIFREADW(reg); + madgemc_setregpage(dev, 0); + } + return ret; +} + +/* + * Write a word-length value to a register. + */ +static void madgemc_sifwritew(struct net_device *dev, unsigned short val, unsigned short reg) +{ + if (reg<0x8) + SIFWRITEW(val, reg); + else { + madgemc_setregpage(dev, 1); + SIFWRITEW(val, reg); + madgemc_setregpage(dev, 0); + } + return; +} + + + +int __init madgemc_probe(void) +{ + static int versionprinted = 0; + struct net_device *dev; + struct net_local *tp; + struct madgemc_card *card; + int i,slot = 0; + __u8 posreg[4]; + + if (!MCA_bus) + return -1; + + while (slot != MCA_NOTFOUND) { + /* + * Currently we only support the MC16/32 (MCA ID 002d) + */ + slot = mca_find_unused_adapter(0x002d, slot); + if (slot == MCA_NOTFOUND) + break; + + /* + * If we get here, we have an adapter. + */ + if (versionprinted++ == 0) + printk("%s", version); + + if ((dev = init_trdev(NULL, 0))==NULL) { + printk("madgemc: unable to allocate dev space\n"); + return -1; + } + dev->dma = 0; + + /* + * Fetch MCA config registers + */ + for(i=0;i<4;i++) + posreg[i] = mca_read_stored_pos(slot, i+2); + + card = kmalloc(sizeof(struct madgemc_card), GFP_KERNEL); + if (card==NULL) { + printk("madgemc: unable to allocate card struct\n"); + return -1; + } + card->dev = dev; + + /* + * Parse configuration information. This all comes + * directly from the publicly available @002d.ADF. + * Get it from Madge or your local ADF library. + */ + + /* + * Base address + */ + dev->base_addr = 0x0a20 + + ((posreg[2] & MC16_POS2_ADDR2)?0x0400:0) + + ((posreg[0] & MC16_POS0_ADDR1)?0x1000:0) + + ((posreg[3] & MC16_POS3_ADDR3)?0x2000:0); + + /* + * Interrupt line + */ + switch(posreg[0] >> 6) { /* upper two bits */ + case 0x1: dev->irq = 3; break; + case 0x2: dev->irq = 9; break; /* IRQ 2 = IRQ 9 */ + case 0x3: dev->irq = 10; break; + default: dev->irq = 0; break; + } + + if (dev->irq == 0) { + printk("%s: invalid IRQ\n", dev->name); + goto getout; + } + + request_region(dev->base_addr, MADGEMC_IO_EXTENT, "madgemc"); +#if 0 + /* why is this not working? */ + if (request_region(dev->base_addr, MADGEMC_IO_EXTENT, + "madgemc")) { + printk(KERN_INFO "madgemc: unable to setup Smart MC in slot %d because of I/O base conflict at 0x%04lx\n", slot, dev->base_addr); + dev->base_addr += MADGEMC_SIF_OFFSET; + goto getout; + } +#endif + dev->base_addr += MADGEMC_SIF_OFFSET; + + /* + * Arbitration Level + */ + card->arblevel = ((posreg[0] >> 1) & 0x7) + 8; + + /* + * Burst mode and Fairness + */ + card->burstmode = ((posreg[2] >> 6) & 0x3); + card->fairness = ((posreg[2] >> 4) & 0x1); + + /* + * Ring Speed + */ + if ((posreg[1] >> 2)&0x1) + card->ringspeed = 2; /* not selected */ + else if ((posreg[2] >> 5) & 0x1) + card->ringspeed = 1; /* 16Mb */ + else + card->ringspeed = 0; /* 4Mb */ + + /* + * Cable type + */ + if ((posreg[1] >> 6)&0x1) + card->cabletype = 1; /* STP/DB9 */ + else + card->cabletype = 0; /* UTP/RJ-45 */ + + + /* + * ROM Info. This requires us to actually twiddle + * bits on the card, so we must ensure above that + * the base address is free of conflict (request_region above). + */ + madgemc_read_rom(card); + + if (card->manid != 0x4d) { /* something went wrong */ + printk(KERN_INFO "%s: Madge MC ROM read failed (unknown manufacturer ID %02x)\n", dev->name, card->manid); + goto getout; + } + + if ((card->cardtype != 0x08) && (card->cardtype != 0x0d)) { + printk(KERN_INFO "%s: Madge MC ROM read failed (unknown card ID %02x)\n", dev->name, card->cardtype); + goto getout; + } + + /* All cards except Rev 0 and 1 MC16's have 256kb of RAM */ + if ((card->cardtype == 0x08) && (card->cardrev <= 0x01)) + card->ramsize = 128; + else + card->ramsize = 256; + + printk("%s: %s Rev %d at 0x%04lx IRQ %d\n", + dev->name, + (card->cardtype == 0x08)?MADGEMC16_CARDNAME: + MADGEMC32_CARDNAME, card->cardrev, + dev->base_addr, dev->irq); + + if (card->cardtype == 0x0d) + printk("%s: Warning: MC32 support is experimental and highly untested\n", dev->name); + + if (card->ringspeed==2) { /* Unknown */ + printk("%s: Warning: Ring speed not set in POS -- Please run the reference disk and set it!\n", dev->name); + card->ringspeed = 1; /* default to 16mb */ + } + + printk("%s: RAM Size: %dKB\n", dev->name, card->ramsize); + + printk("%s: Ring Speed: %dMb/sec on %s\n", dev->name, + (card->ringspeed)?16:4, + card->cabletype?"STP/DB9":"UTP/RJ-45"); + printk("%s: Arbitration Level: %d\n", dev->name, + card->arblevel); + + printk("%s: Burst Mode: ", dev->name); + switch(card->burstmode) { + case 0: printk("Cycle steal"); break; + case 1: printk("Limited burst"); break; + case 2: printk("Delayed release"); break; + case 3: printk("Immediate release"); break; + } + printk(" (%s)\n", (card->fairness)?"Unfair":"Fair"); + + + /* + * Enable SIF before we assign the interrupt handler, + * just in case we get spurious interrupts that need + * handling. + */ + outb(0, dev->base_addr + MC_CONTROL_REG0); /* sanity */ + madgemc_setsifsel(dev, 1); + if(request_irq(dev->irq, madgemc_interrupt, SA_SHIRQ, + "madgemc", dev)) + goto getout; + + madgemc_chipset_init(dev); /* enables interrupts! */ + madgemc_setcabletype(dev, card->cabletype); + + /* Setup MCA structures */ + mca_set_adapter_name(slot, (card->cardtype == 0x08)?MADGEMC16_CARDNAME:MADGEMC32_CARDNAME); + mca_set_adapter_procfn(slot, madgemc_mcaproc, dev); + mca_mark_as_used(slot); + + printk("%s: Ring Station Address: ", dev->name); + printk("%2.2x", dev->dev_addr[0]); + for (i = 1; i < 6; i++) + printk(":%2.2x", dev->dev_addr[i]); + printk("\n"); + + if (tmsdev_init(dev)) { + printk("%s: unable to get memory for dev->priv.\n", + dev->name); + return -1; + } + tp = (struct net_local *)dev->priv; + + /* + * The MC16 is physically a 32bit card. However, Madge + * insists on calling it 16bit, so I'll assume here that + * they know what they're talking about. Cut off DMA + * at 16mb. + */ + tp->dmalimit = ISA_MAX_ADDRESS; /* XXX: ?? */ + tp->setnselout = madgemc_setnselout_pins; + tp->sifwriteb = madgemc_sifwriteb; + tp->sifreadb = madgemc_sifreadb; + tp->sifwritew = madgemc_sifwritew; + tp->sifreadw = madgemc_sifreadw; + tp->DataRate = (card->ringspeed)?SPEED_16:SPEED_4; + + memcpy(tp->ProductID, "Madge MCA 16/4 ", PROD_ID_SIZE + 1); + + dev->open = madgemc_open; + dev->stop = madgemc_close; + + if (register_trdev(dev) == 0) { + /* Enlist in the card list */ + card->next = madgemc_card_list; + madgemc_card_list = card; + } else { + printk("madgemc: register_trdev() returned non-zero.\n"); + + kfree(card); + kfree(dev->priv); + kfree(dev); + return -1; + } + + slot++; + continue; /* successful, try to find another */ + + getout: + release_region(dev->base_addr-MADGEMC_SIF_OFFSET, + MADGEMC_IO_EXTENT); + kfree(card); + kfree(dev); /* release_trdev? */ + slot++; + } + + if (madgemc_card_list) + return 0; + return -1; +} + +/* + * Handle interrupts generated by the card + * + * The MicroChannel Madge cards need slightly more handling + * after an interrupt than other TMS380 cards do. + * + * First we must make sure it was this card that generated the + * interrupt (since interrupt sharing is allowed). Then, + * because we're using level-triggered interrupts (as is + * standard on MCA), we must toggle the interrupt line + * on the card in order to claim and acknowledge the interrupt. + * Once that is done, the interrupt should be handlable in + * the normal tms380tr_interrupt() routine. + * + * There's two ways we can check to see if the interrupt is ours, + * both with their own disadvantages... + * + * 1) Read in the SIFSTS register from the TMS controller. This + * is guarenteed to be accurate, however, there's a fairly + * large performance penalty for doing so: the Madge chips + * must request the register from the Eagle, the Eagle must + * read them from its internal bus, and then take the route + * back out again, for a 16bit read. + * + * 2) Use the MC_CONTROL_REG0_SINTR bit from the Madge ASICs. + * The major disadvantage here is that the accuracy of the + * bit is in question. However, it cuts out the extra read + * cycles it takes to read the Eagle's SIF, as its only an + * 8bit read, and theoretically the Madge bit is directly + * connected to the interrupt latch coming out of the Eagle + * hardware (that statement is not verified). + * + * I can't determine which of these methods has the best win. For now, + * we make a compromise. Use the Madge way for the first interrupt, + * which should be the fast-path, and then once we hit the first + * interrupt, keep on trying using the SIF method until we've + * exhausted all contiguous interrupts. + * + */ +static void madgemc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + int pending,reg1; + struct net_device *dev; + + if (!dev_id) { + printk("madgemc_interrupt: was not passed a dev_id!\n"); + return; + } + + dev = (struct net_device *)dev_id; + + /* Make sure its really us. -- the Madge way */ + pending = inb(dev->base_addr + MC_CONTROL_REG0); + if (!(pending & MC_CONTROL_REG0_SINTR)) + return; /* not our interrupt */ + + /* + * Since we're level-triggered, we may miss the rising edge + * of the next interrupt while we're off handling this one, + * so keep checking until the SIF verifies that it has nothing + * left for us to do. + */ + pending = STS_SYSTEM_IRQ; + do { + if (pending & STS_SYSTEM_IRQ) { + + /* Toggle the interrupt to reset the latch on card */ + reg1 = inb(dev->base_addr + MC_CONTROL_REG1); + outb(reg1 ^ MC_CONTROL_REG1_SINTEN, + dev->base_addr + MC_CONTROL_REG1); + outb(reg1, dev->base_addr + MC_CONTROL_REG1); + + /* Continue handling as normal */ + tms380tr_interrupt(irq, dev_id, regs); + + pending = SIFREADW(SIFSTS); /* restart - the SIF way */ + + } else + return; + } while (1); + + return; /* not reachable */ +} + +/* + * Set the card to the prefered ring speed. + * + * Unlike newer cards, the MC16/32 have their speed selection + * circuit connected to the Madge ASICs and not to the TMS380 + * NSELOUT pins. Set the ASIC bits correctly here, and return + * zero to leave the TMS NSELOUT bits unaffected. + * + */ +unsigned short madgemc_setnselout_pins(struct net_device *dev) +{ + unsigned char reg1; + struct net_local *tp = (struct net_local *)dev->priv; + + reg1 = inb(dev->base_addr + MC_CONTROL_REG1); + + if(tp->DataRate == SPEED_16) + reg1 |= MC_CONTROL_REG1_SPEED_SEL; /* add for 16mb */ + else if (reg1 & MC_CONTROL_REG1_SPEED_SEL) + reg1 ^= MC_CONTROL_REG1_SPEED_SEL; /* remove for 4mb */ + outb(reg1, dev->base_addr + MC_CONTROL_REG1); + + return 0; /* no change */ +} + +/* + * Set the register page. This equates to the SRSX line + * on the TMS380Cx6. + * + * Register selection is normally done via three contiguous + * bits. However, some boards (such as the MC16/32) use only + * two bits, plus a seperate bit in the glue chip. This + * sets the SRSX bit (the top bit). See page 4-17 in the + * Yellow Book for which registers are affected. + * + */ +static void madgemc_setregpage(struct net_device *dev, int page) +{ + static int reg1 = 0; + + reg1 = inb(dev->base_addr + MC_CONTROL_REG1); + if ((page == 0) && (reg1 & MC_CONTROL_REG1_SRSX)) { + outb(reg1 ^ MC_CONTROL_REG1_SRSX, + dev->base_addr + MC_CONTROL_REG1); + } + else if (page == 1) { + outb(reg1 | MC_CONTROL_REG1_SRSX, + dev->base_addr + MC_CONTROL_REG1); + } + reg1 = inb(dev->base_addr + MC_CONTROL_REG1); + + return; +} + +/* + * The SIF registers are not mapped into register space by default + * Set this to 1 to map them, 0 to map the BIA ROM. + * + */ +static void madgemc_setsifsel(struct net_device *dev, int val) +{ + unsigned int reg0; + + reg0 = inb(dev->base_addr + MC_CONTROL_REG0); + if ((val == 0) && (reg0 & MC_CONTROL_REG0_SIFSEL)) { + outb(reg0 ^ MC_CONTROL_REG0_SIFSEL, + dev->base_addr + MC_CONTROL_REG0); + } else if (val == 1) { + outb(reg0 | MC_CONTROL_REG0_SIFSEL, + dev->base_addr + MC_CONTROL_REG0); + } + reg0 = inb(dev->base_addr + MC_CONTROL_REG0); + + return; +} + +/* + * Enable SIF interrupts + * + * This does not enable interrupts in the SIF, but rather + * enables SIF interrupts to be passed onto the host. + * + */ +static void madgemc_setint(struct net_device *dev, int val) +{ + unsigned int reg1; + + reg1 = inb(dev->base_addr + MC_CONTROL_REG1); + if ((val == 0) && (reg1 & MC_CONTROL_REG1_SINTEN)) { + outb(reg1 ^ MC_CONTROL_REG1_SINTEN, + dev->base_addr + MC_CONTROL_REG1); + } else if (val == 1) { + outb(reg1 | MC_CONTROL_REG1_SINTEN, + dev->base_addr + MC_CONTROL_REG1); + } + + return; +} + +/* + * Cable type is set via control register 7. Bit zero high + * for UTP, low for STP. + */ +static void madgemc_setcabletype(struct net_device *dev, int type) +{ + outb((type==0)?MC_CONTROL_REG7_CABLEUTP:MC_CONTROL_REG7_CABLESTP, + dev->base_addr + MC_CONTROL_REG7); +} + +/* + * Enable the functions of the Madge chipset needed for + * full working order. + */ +static int madgemc_chipset_init(struct net_device *dev) +{ + outb(0, dev->base_addr + MC_CONTROL_REG1); /* pull SRESET low */ + tms380tr_wait(100); /* wait for card to reset */ + + /* bring back into normal operating mode */ + outb(MC_CONTROL_REG1_NSRESET, dev->base_addr + MC_CONTROL_REG1); + + /* map SIF registers */ + madgemc_setsifsel(dev, 1); + + /* enable SIF interrupts */ + madgemc_setint(dev, 1); + + return 0; +} + +/* + * Disable the board, and put back into power-up state. + */ +void madgemc_chipset_close(struct net_device *dev) +{ + /* disable interrupts */ + madgemc_setint(dev, 0); + /* unmap SIF registers */ + madgemc_setsifsel(dev, 0); + + return; +} + +/* + * Read the card type (MC16 or MC32) from the card. + * + * The configuration registers are stored in two seperate + * pages. Pages are flipped by clearing bit 3 of CONTROL_REG0 (PAGE) + * for page zero, or setting bit 3 for page one. + * + * Page zero contains the following data: + * Byte 0: Manufacturer ID (0x4D -- ASCII "M") + * Byte 1: Card type: + * 0x08 for MC16 + * 0x0D for MC32 + * Byte 2: Card revision + * Byte 3: Mirror of POS config register 0 + * Byte 4: Mirror of POS 1 + * Byte 5: Mirror of POS 2 + * + * Page one contains the following data: + * Byte 0: Unused + * Byte 1-6: BIA, MSB to LSB. + * + * Note that to read the BIA, we must unmap the SIF registers + * by clearing bit 2 of CONTROL_REG0 (SIFSEL), as the data + * will reside in the same logical location. For this reason, + * _never_ read the BIA while the Eagle processor is running! + * The SIF will be completely inaccessible until the BIA operation + * is complete. + * + */ +static void madgemc_read_rom(struct madgemc_card *card) +{ + unsigned long ioaddr; + unsigned char reg0, reg1, tmpreg0, i; + + ioaddr = card->dev->base_addr; + + reg0 = inb(ioaddr + MC_CONTROL_REG0); + reg1 = inb(ioaddr + MC_CONTROL_REG1); + + /* Switch to page zero and unmap SIF */ + tmpreg0 = reg0 & ~(MC_CONTROL_REG0_PAGE + MC_CONTROL_REG0_SIFSEL); + outb(tmpreg0, ioaddr + MC_CONTROL_REG0); + + card->manid = inb(ioaddr + MC_ROM_MANUFACTURERID); + card->cardtype = inb(ioaddr + MC_ROM_ADAPTERID); + card->cardrev = inb(ioaddr + MC_ROM_REVISION); + + /* Switch to rom page one */ + outb(tmpreg0 | MC_CONTROL_REG0_PAGE, ioaddr + MC_CONTROL_REG0); + + /* Read BIA */ + card->dev->addr_len = 6; + for (i = 0; i < 6; i++) + card->dev->dev_addr[i] = inb(ioaddr + MC_ROM_BIA_START + i); + + /* Restore original register values */ + outb(reg0, ioaddr + MC_CONTROL_REG0); + outb(reg1, ioaddr + MC_CONTROL_REG1); + + return; +} + +static int madgemc_open(struct net_device *dev) +{ + /* + * Go ahead and reinitialize the chipset again, just to + * make sure we didn't get left in a bad state. + */ + madgemc_chipset_init(dev); + tms380tr_open(dev); + MOD_INC_USE_COUNT; + return 0; +} + +static int madgemc_close(struct net_device *dev) +{ + tms380tr_close(dev); + madgemc_chipset_close(dev); + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * Give some details available from /proc/mca/slotX + */ +static int madgemc_mcaproc(char *buf, int slot, void *d) +{ + struct net_device *dev = (struct net_device *)d; + struct madgemc_card *curcard = madgemc_card_list; + int len = 0; + + while (curcard) { /* search for card struct */ + if (curcard->dev == dev) + break; + curcard = curcard->next; + } + len += sprintf(buf+len, "-------\n"); + if (curcard) { + struct net_local *tp = (struct net_local *)dev->priv; + int i; + + len += sprintf(buf+len, "Card Revision: %d\n", curcard->cardrev); + len += sprintf(buf+len, "RAM Size: %dkb\n", curcard->ramsize); + len += sprintf(buf+len, "Cable type: %s\n", (curcard->cabletype)?"STP/DB9":"UTP/RJ-45"); + len += sprintf(buf+len, "Configured ring speed: %dMb/sec\n", (curcard->ringspeed)?16:4); + len += sprintf(buf+len, "Running ring speed: %dMb/sec\n", (tp->DataRate==SPEED_16)?16:4); + len += sprintf(buf+len, "Device: %s\n", dev->name); + len += sprintf(buf+len, "IO Port: 0x%04lx\n", dev->base_addr); + len += sprintf(buf+len, "IRQ: %d\n", dev->irq); + len += sprintf(buf+len, "Arbitration Level: %d\n", curcard->arblevel); + len += sprintf(buf+len, "Burst Mode: "); + switch(curcard->burstmode) { + case 0: len += sprintf(buf+len, "Cycle steal"); break; + case 1: len += sprintf(buf+len, "Limited burst"); break; + case 2: len += sprintf(buf+len, "Delayed release"); break; + case 3: len += sprintf(buf+len, "Immediate release"); break; + } + len += sprintf(buf+len, " (%s)\n", (curcard->fairness)?"Unfair":"Fair"); + + len += sprintf(buf+len, "Ring Station Address: "); + len += sprintf(buf+len, "%2.2x", dev->dev_addr[0]); + for (i = 1; i < 6; i++) + len += sprintf(buf+len, " %2.2x", dev->dev_addr[i]); + len += sprintf(buf+len, "\n"); + } else + len += sprintf(buf+len, "Card not configured\n"); + + return len; +} + +#ifdef MODULE + +int init_module(void) +{ + /* Probe for cards. */ + if (madgemc_probe()) { + printk(KERN_NOTICE "madgemc.c: No cards found.\n"); + } + /* lock_tms380_module(); */ + return (0); +} + +void cleanup_module(void) +{ + struct net_device *dev; + struct madgemc_card *this_card; + + while (madgemc_card_list) { + dev = madgemc_card_list->dev; + unregister_trdev(dev); + release_region(dev->base_addr-MADGEMC_SIF_OFFSET, MADGEMC_IO_EXTENT); + free_irq(dev->irq, dev); + kfree(dev->priv); + kfree(dev); + this_card = madgemc_card_list; + madgemc_card_list = this_card->next; + kfree(this_card); + } + /* unlock_tms380_module(); */ +} +#endif /* MODULE */ + + +/* + * Local variables: + * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c madgemc.c" + * alt-compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c madgemc.c" + * c-set-style "K&R" + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff -ru --new-file 2.3.40.clean/drivers/net/tokenring/madgemc.h 2.3.40/drivers/net/tokenring/madgemc.h --- 2.3.40.clean/drivers/net/tokenring/madgemc.h Thu Jan 1 00:00:00 1970 +++ 2.3.40/drivers/net/tokenring/madgemc.h Sun Jan 23 05:23:36 2000 @@ -0,0 +1,70 @@ +/* + * madgemc.h: Header for the madgemc tms380tr module + * + * Authors: + * - Adam Fritzler + */ + +#ifndef __LINUX_MADGEMC_H +#define __LINUX_MADGEMC_H + +#ifdef __KERNEL__ + +#define MADGEMC16_CARDNAME "Madge Smart 16/4 MC16 Ringnode" +#define MADGEMC32_CARDNAME "Madge Smart 16/4 MC32 Ringnode" + +/* + * Bit definitions for the POS config registers + */ +#define MC16_POS0_ADDR1 0x20 +#define MC16_POS2_ADDR2 0x04 +#define MC16_POS3_ADDR3 0x20 + +#define MC_CONTROL_REG0 ((long)-8) /* 0x00 */ +#define MC_CONTROL_REG1 ((long)-7) /* 0x01 */ +#define MC_ADAPTER_POS_REG0 ((long)-6) /* 0x02 */ +#define MC_ADAPTER_POS_REG1 ((long)-5) /* 0x03 */ +#define MC_ADAPTER_POS_REG2 ((long)-4) /* 0x04 */ +#define MC_ADAPTER_REG5_UNUSED ((long)-3) /* 0x05 */ +#define MC_ADAPTER_REG6_UNUSED ((long)-2) /* 0x06 */ +#define MC_CONTROL_REG7 ((long)-1) /* 0x07 */ + +#define MC_CONTROL_REG0_UNKNOWN1 0x01 +#define MC_CONTROL_REG0_UNKNOWN2 0x02 +#define MC_CONTROL_REG0_SIFSEL 0x04 +#define MC_CONTROL_REG0_PAGE 0x08 +#define MC_CONTROL_REG0_TESTINTERRUPT 0x10 +#define MC_CONTROL_REG0_UNKNOWN20 0x20 +#define MC_CONTROL_REG0_SINTR 0x40 +#define MC_CONTROL_REG0_UNKNOWN80 0x80 + +#define MC_CONTROL_REG1_SINTEN 0x01 +#define MC_CONTROL_REG1_BITOFDEATH 0x02 +#define MC_CONTROL_REG1_NSRESET 0x04 +#define MC_CONTROL_REG1_UNKNOWN8 0x08 +#define MC_CONTROL_REG1_UNKNOWN10 0x10 +#define MC_CONTROL_REG1_UNKNOWN20 0x20 +#define MC_CONTROL_REG1_SRSX 0x40 +#define MC_CONTROL_REG1_SPEED_SEL 0x80 + +#define MC_CONTROL_REG7_CABLESTP 0x00 +#define MC_CONTROL_REG7_CABLEUTP 0x01 + +/* + * ROM Page Zero + */ +#define MC_ROM_MANUFACTURERID 0x00 +#define MC_ROM_ADAPTERID 0x01 +#define MC_ROM_REVISION 0x02 +#define MC_ROM_CONFIG0 0x03 +#define MC_ROM_CONFIG1 0x04 +#define MC_ROM_CONFIG2 0x05 + +/* + * ROM Page One + */ +#define MC_ROM_UNUSED_BYTE 0x00 +#define MC_ROM_BIA_START 0x01 + +#endif /* __KERNEL__ */ +#endif /* __LINUX_MADGEMC_H */ diff -ru --new-file 2.3.40.clean/drivers/net/tokenring/tms380tr.c 2.3.40/drivers/net/tokenring/tms380tr.c --- 2.3.40.clean/drivers/net/tokenring/tms380tr.c Sun Jan 23 05:30:26 2000 +++ 2.3.40/drivers/net/tokenring/tms380tr.c Sun Jan 23 04:40:04 2000 @@ -1,5 +1,5 @@ /* - * tms380tr.c: A network driver for Texas Instruments TMS380-based + * tms380tr.c: A network driver library for Texas Instruments TMS380-based * Token Ring Adapters. * * Originally sktr.c: Written 1997 by Christoph Goos @@ -10,14 +10,16 @@ * This software may be used and distributed according to the terms * of the GNU Public License, incorporated herein by reference. * - * This device driver works with the following TMS380 adapters: + * The following modules are currently available for card support: + * - tmspci (Generic PCI card support) + * - abyss (Madge PCI support) + * + * The following cards are currently lacking support, even + * though they were supported in previous versions, because + * their code did not get migrated into a seperate module: * - SysKonnect TR4/16(+) ISA (SK-4190) - * - SysKonnect TR4/16(+) PCI (SK-4590) - * - SysKonnect TR4/16 PCI (SK-4591) - * - Compaq TR 4/16 PCI - * - Thomas-Conrad TC4048 4/16 PCI - * - 3Com 3C339 Token Link Velocity - * - Any ISA or PCI adapter using only the TMS380 chipset + * They are no longer supported by this driver, at least until + * a module gets written for them. * * Sources: * - The hardware related parts of this driver are take from @@ -27,14 +29,16 @@ * - Also various other drivers in the linux source tree were taken * as samples for some tasks. * - TI TMS380 Second-Generation Token Ring User's Guide - * - TI datasheets for respective chips - * - David Hein at Texas Instruments + * - TI datasheets for respective chips + * - David Hein at Texas Instruments + * - Various Madge employees * * Maintainer(s): * JS Jay Schulist jschlst@turbolinux.com * CG Christoph Goos cgoos@syskonnect.de * AF Adam Fritzler mid@auk.cx - * + * MLP Mike Phillips phillim@amtrak.com + * * Modification History: * 29-Aug-97 CG Created * 04-Apr-98 CG Fixed problems caused by tok_timer_check @@ -42,22 +46,33 @@ * 27-May-98 JS Formated to Linux Kernel Format * 31-May-98 JS Hacked in PCI support * 16-Jun-98 JS Modulized for multiple cards with one driver - * Sep-99 AF Renamed to tms380tr (supports more than SK's) + * Sep-99 AF Renamed to tms380tr (supports more than SK's) * 23-Sep-99 AF Added Compaq and Thomas-Conrad PCI support * Fixed a bug causing double copies on PCI * Fixed for new multicast stuff (2.2/2.3) * 25-Sep-99 AF Uped TPL_NUM from 3 to 9 * Removed extraneous 'No free TPL' + * 22-Dec-99 AF Added Madge PCI Mk2 support and generalized + * parts of the initilization procedure. + * 30-Dec-99 AF Turned tms380tr into a library ala 8390. + * Madge support is provided in the abyss module + * Generic PCI support is in the tmspci module. * * To do: - * 1. Selectable 16 Mbps or 4Mbps - * 2. Multi/Broadcast packet handling (this may have fixed itself) - * + * 1. Multi/Broadcast packet handling (this may have fixed itself) + * 2. Write a sktrisa module that includes the old ISA support + * 3. Allow modules to load their own microcode + * 4. Speed up the BUD process -- freezing the kernel for 3+sec is + * quite unacceptable. + * 5. Still a few remaining stalls when the cable is unplugged. */ -static const char *version = "tms380tr.c: v1.03 29/09/1999 by Christoph Goos, Adam Fritzler\n"; +#ifdef MODULE +static const char *version = "tms380tr.c: v1.07 21/01/2000 by Christoph Goos, Adam Fritzler\n"; +#endif #ifdef MODULE +#define EXPORT_SYMTAB #include #include #endif @@ -78,6 +93,7 @@ #include #include #include +#include #include #include #include @@ -90,45 +106,6 @@ #include "tms380tr.h" /* Our Stuff */ #include "tms380tr_microcode.h" /* TI microcode for COMMprocessor */ -/* A zero-terminated list of I/O addresses to be probed. */ -static unsigned int tms380tr_portlist[] __initdata = { - 0x0A20, 0x1A20, 0x0B20, 0x1B20, 0x0980, 0x1980, 0x0900, 0x1900, - 0 -}; - -/* A zero-terminated list of IRQs to be probed. - * Used again after initial probe for tms380tr_chipset_init, called from tms380tr_open. - */ -static unsigned short tms380tr_irqlist[] = { - 3, 5, 9, 10, 11, 12, 15, - 0 -}; - -/* A zero-terminated list of DMAs to be probed. */ -static int tms380tr_dmalist[] __initdata = { - 5, 6, 7, - 0 -}; - -/* - * Table used for card detection and type determination. - */ -struct cardinfo_table cardinfo[] = { - { 0, 0, 0, - "Unknown TMS380 Token Ring Adapter"}, - { TMS_ISA, 0, 0, - "SK NET TR 4/16 ISA"}, - { TMS_PCI, PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TOKENRING, - "Compaq 4/16 TR PCI"}, - { TMS_PCI, PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_TR, - "SK NET TR 4/16 PCI"}, - { TMS_PCI, PCI_VENDOR_ID_TCONRAD, PCI_DEVICE_ID_TCONRAD_TOKENRING, - "Thomas-Conrad TC4048 PCI 4/16"}, - { TMS_PCI, PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C339, - "3Com Token Link Velocity"}, - { 0, 0, 0, NULL} -}; - /* Use 0 for production, 1 for verification, 2 for debug, and * 3 for very verbose debug. */ @@ -137,24 +114,24 @@ #endif static unsigned int tms380tr_debug = TMS380TR_DEBUG; -/* The number of low I/O ports used by the tokencard. */ -#define TMS380TR_IO_EXTENT 32 - /* Index to functions, as function prototypes. * Alphabetical by function name. */ +/* "A" */ /* "B" */ static int tms380tr_bringup_diags(struct net_device *dev); /* "C" */ static void tms380tr_cancel_tx_queue(struct net_local* tp); static int tms380tr_chipset_init(struct net_device *dev); static void tms380tr_chk_irq(struct net_device *dev); +#if 0 static unsigned char tms380tr_chk_frame(struct net_device *dev, unsigned char *Addr); +#endif static void tms380tr_chk_outstanding_cmds(struct net_device *dev); static void tms380tr_chk_src_addr(unsigned char *frame, unsigned char *hw_addr); static unsigned char tms380tr_chk_ssb(struct net_local *tp, unsigned short IrqType); -static int tms380tr_close(struct net_device *dev); +int tms380tr_close(struct net_device *dev); static void tms380tr_cmd_status_irq(struct net_device *dev); /* "D" */ static void tms380tr_disable_interrupts(struct net_device *dev); @@ -176,20 +153,15 @@ static int tms380tr_init_card(struct net_device *dev); static void tms380tr_init_ipb(struct net_local *tp); static void tms380tr_init_net_local(struct net_device *dev); -static void tms380tr_init_opb(struct net_local *tp); -static void tms380tr_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static int tms380tr_isa_chk_card(struct net_device *dev, int ioaddr, struct cardinfo_table **outcard); -static int tms380tr_isa_chk_ioaddr(int ioaddr); +static void tms380tr_init_opb(struct net_device *dev); +void tms380tr_interrupt(int irq, void *dev_id, struct pt_regs *regs); +/* "M" */ /* "O" */ -static int tms380tr_open(struct net_device *dev); +int tms380tr_open(struct net_device *dev); static void tms380tr_open_adapter(struct net_device *dev); /* "P" */ -static int tms380tr_pci_chk_card(struct net_device *dev, struct cardinfo_table **outcard); -int tms380tr_probe(struct net_device *dev); -static int tms380tr_probe1(struct net_device *dev, int ioaddr); /* "R" */ static void tms380tr_rcv_status_irq(struct net_device *dev); -static void tms380tr_read_addr(struct net_device *dev, unsigned char *Address); static int tms380tr_read_ptr(struct net_device *dev); static void tms380tr_read_ram(struct net_device *dev, unsigned char *Data, unsigned short Address, int Length); @@ -199,6 +171,7 @@ /* "S" */ static int tms380tr_send_packet(struct sk_buff *skb, struct net_device *dev); static void tms380tr_set_multicast_list(struct net_device *dev); +static int tms380tr_set_mac_address(struct net_device *dev, void *addr); /* "T" */ static void tms380tr_timer_chk(unsigned long data); static void tms380tr_timer_end_wait(unsigned long data); @@ -207,269 +180,61 @@ static void tms380tr_update_rcv_stats(struct net_local *tp, unsigned char DataPtr[], unsigned int Length); /* "W" */ -static void tms380tr_wait(unsigned long time); +void tms380tr_wait(unsigned long time); static void tms380tr_write_rpl_status(RPL *rpl, unsigned int Status); static void tms380tr_write_tpl_status(TPL *tpl, unsigned int Status); -/* - * Check for a network adapter of this type, and return '0' if one exists. - * If dev->base_addr == 0, probe all likely locations. - * If dev->base_addr == 1, always return failure. - */ -int __init tms380tr_probe(struct net_device *dev) -{ - int i; - int base_addr = dev ? dev->base_addr : 0; - - if(base_addr > 0x1ff) /* Check a single specified location. */ - return (tms380tr_probe1(dev, base_addr)); - else if(base_addr != 0) /* Don't probe at all. */ - return (-ENXIO); - - /* - * Let's check for pci adapters first - */ - if (tms380tr_probe1(dev,0) == 0) /* Success */ - return 0 ; - - /* - * No pci cards found, let's check for isa - */ +#define SIFREADB(reg) (((struct net_local *)dev->priv)->sifreadb(dev, reg)) +#define SIFWRITEB(val, reg) (((struct net_local *)dev->priv)->sifwriteb(dev, val, reg)) +#define SIFREADW(reg) (((struct net_local *)dev->priv)->sifreadw(dev, reg)) +#define SIFWRITEW(val, reg) (((struct net_local *)dev->priv)->sifwritew(dev, val, reg)) - for(i = 0; tms380tr_portlist[i]; i++) - { - int ioaddr = tms380tr_portlist[i]; - if(check_region(ioaddr, TMS380TR_IO_EXTENT)) /* Region already used */ - continue; - if(!tms380tr_probe1(dev, ioaddr)) - return (0); - } - return (-ENODEV); -} -struct cardinfo_table * __init tms380tr_pci_getcardinfo(unsigned short vendor, - unsigned short device) +#if TMS380TR_DEBUG > 0 +static int madgemc_sifprobe(struct net_device *dev) { - int cur; - for (cur = 1; cardinfo[cur].name != NULL; cur++) { - if (cardinfo[cur].type == 2) /* PCI */ - { - if ((cardinfo[cur].vendor_id == vendor) && (cardinfo[cur].device_id == device)) - return &cardinfo[cur]; - } - } + unsigned char old, chk1, chk2; - return NULL; -} + old = SIFREADB(SIFADR); /* Get the old SIFADR value */ -/* - * Detect and setup the PCI SysKonnect TR cards in slot order. - */ -static int __init tms380tr_pci_chk_card(struct net_device *dev, - struct cardinfo_table **outcard) -{ - struct pci_dev *pci_device = NULL ; - struct cardinfo_table *card; - int i; - - if(!pci_present()) - return (-1); /* No PCI present. */ - - while ( (pci_device=pci_find_class(PCI_CLASS_NETWORK_TOKEN_RING<<8, pci_device))) { - - unsigned int pci_irq_line; - unsigned int pci_ioaddr; - - /* Remove I/O space marker in bit 0. */ - pci_irq_line = pci_device->irq ; - pci_ioaddr = pci_device->resource[0].start ; -/* pci_ioaddr &= ~3; */ - - /* Don't return from here, just continue on the card discovery loop - MLP */ - if (!(card = tms380tr_pci_getcardinfo(pci_device->vendor, pci_device->device))) - continue ; - - if(check_region(pci_ioaddr, TMS380TR_IO_EXTENT)) - continue; - - request_region(pci_ioaddr, TMS380TR_IO_EXTENT, card->name); - if(request_irq(pci_device->irq, tms380tr_interrupt, SA_SHIRQ, - card->name, dev)) { - release_region(pci_ioaddr, TMS380TR_IO_EXTENT) ; - return (-ENODEV); /* continue; ?? */ - } - /* At this point we have found a valid tms380tr PCI TR card. */ - - pci_ioaddr &= ~3 ; - dev->base_addr = pci_ioaddr; - dev->irq = pci_irq_line; - dev->dma = 0; - - dev->addr_len = 6; - tms380tr_read_addr(dev, (unsigned char*)dev->dev_addr); + chk1 = 0; /* Begin with check value 0 */ + do { + madgemc_setregpage(dev, 0); + /* Write new SIFADR value */ + SIFWRITEB(chk1, SIFADR); + chk2 = SIFREADB(SIFADR); + if (chk2 != chk1) + return -1; - printk("%s: %s found at %#4x, IRQ %d, ring station ", - dev->name, card->name, pci_ioaddr, dev->irq); - printk("%2.2x", dev->dev_addr[0]); - for (i = 1; i < 6; i++) - printk(":%2.2x", dev->dev_addr[i]); - printk(".\n"); - - if (outcard) - *outcard = card; + madgemc_setregpage(dev, 1); + /* Read, invert and write */ + chk2 = SIFREADB(SIFADD); + if (chk2 != chk1) + return -1; + + madgemc_setregpage(dev, 0); + chk2 ^= 0x0FE; + SIFWRITEB(chk2, SIFADR); + + /* Read, invert and compare */ + madgemc_setregpage(dev, 1); + chk2 = SIFREADB(SIFADD); + madgemc_setregpage(dev, 0); + chk2 ^= 0x0FE; + + if(chk1 != chk2) + return (-1); /* No adapter */ + chk1 -= 2; + } while(chk1 != 0); /* Repeat 128 times (all byte values) */ + + madgemc_setregpage(dev, 0); /* sanity */ + /* Restore the SIFADR value */ + SIFWRITEB(old, SIFADR); - return 0 ; - } - - return (-1); + return (0); } - -/* - * Detect and setup the ISA SysKonnect TR cards. - */ -static int __init tms380tr_isa_chk_card(struct net_device *dev, int ioaddr, - struct cardinfo_table **outcard) -{ - int i, err; - unsigned long flags; - struct cardinfo_table *card = NULL; - - err = tms380tr_isa_chk_ioaddr(ioaddr); - if(err < 0) - return (-ENODEV); - - if(virt_to_bus((void*)((unsigned long)dev->priv+sizeof(struct net_local))) - > ISA_MAX_ADDRESS) - { - printk("%s: Memory not accessible for DMA\n", dev->name); - kfree(dev->priv); - return (-EAGAIN); - } - - /* FIXME */ - card = &cardinfo[1]; - - /* Grab the region so that no one else tries to probe our ioports. */ - request_region(ioaddr, TMS380TR_IO_EXTENT, card->name); - dev->base_addr = ioaddr; - - /* Autoselect IRQ and DMA if dev->irq == 0 */ - if(dev->irq == 0) - { - for(i = 0; tms380tr_irqlist[i] != 0; i++) - { - dev->irq = tms380tr_irqlist[i]; - err = request_irq(dev->irq, &tms380tr_interrupt, 0, card->name, dev); - if(!err) - break; - } - - if(tms380tr_irqlist[i] == 0) - { - printk("%s: AutoSelect no IRQ available\n", dev->name); - return (-EAGAIN); - } - } - else - { - err = request_irq(dev->irq, &tms380tr_interrupt, 0, card->name, dev); - if(err) - { - printk("%s: Selected IRQ not available\n", dev->name); - return (-EAGAIN); - } - } - - /* Always allocate the DMA channel after IRQ and clean up on failure */ - if(dev->dma == 0) - { - for(i = 0; tms380tr_dmalist[i] != 0; i++) - { - dev->dma = tms380tr_dmalist[i]; - err = request_dma(dev->dma, card->name); - if(!err) - break; - } - - if(dev->dma == 0) - { - printk("%s: AutoSelect no DMA available\n", dev->name); - free_irq(dev->irq, NULL); - return (-EAGAIN); - } - } - else - { - err = request_dma(dev->dma, card->name); - if(err) - { - printk("%s: Selected DMA not available\n", dev->name); - free_irq(dev->irq, NULL); - return (-EAGAIN); - } - } - - flags=claim_dma_lock(); - disable_dma(dev->dma); - set_dma_mode(dev->dma, DMA_MODE_CASCADE); - enable_dma(dev->dma); - release_dma_lock(flags); - - printk("%s: %s found at %#4x, using IRQ %d and DMA %d.\n", - dev->name, card->name, ioaddr, dev->irq, dev->dma); - - if (outcard) - *outcard = card; - - return (0); -} - -/* - * Passing an ioaddr of 0 tells us to do a pci card search - */ - -static int __init tms380tr_probe1(struct net_device *dev, int ioaddr) -{ - static unsigned version_printed = 0; - struct net_local *tp; - int err; - struct cardinfo_table *card = NULL; - - if(tms380tr_debug && version_printed++ == 0) - printk(KERN_INFO "%s", version); - -#ifndef MODULE - dev = init_trdev(dev, 0); - if(dev == NULL) - return (-ENOMEM); #endif - if (ioaddr == 0) { - err = tms380tr_pci_chk_card(dev, &card); - } else { - err = tms380tr_isa_chk_card(dev, ioaddr, &card); - } - if(err < 0) - return (-ENODEV); - - /* Setup this devices private information structure */ - tp = (struct net_local *)kmalloc(sizeof(struct net_local), GFP_KERNEL | GFP_DMA); - if(tp == NULL) - return (-ENOMEM); - memset(tp, 0, sizeof(struct net_local)); - init_waitqueue_head(&tp->wait_for_tok_int); - tp->CardType = card; - - dev->priv = tp; - dev->init = tms380tr_init_card; - dev->open = tms380tr_open; - dev->stop = tms380tr_close; - dev->do_ioctl = NULL ; - dev->hard_start_xmit = tms380tr_send_packet; - dev->get_stats = tms380tr_get_stats; - dev->set_multicast_list = &tms380tr_set_multicast_list; - return (0); -} /* Dummy function */ static int __init tms380tr_init_card(struct net_device *dev) @@ -481,42 +246,6 @@ } /* - * This function tests if an adapter is really installed at the - * given I/O address. Return negative if no adapter at IO addr. - */ -static int __init tms380tr_isa_chk_ioaddr(int ioaddr) -{ - unsigned char old, chk1, chk2; - - old = inb(ioaddr + SIFADR); /* Get the old SIFADR value */ - - chk1 = 0; /* Begin with check value 0 */ - do { - /* Write new SIFADR value */ - outb(chk1, ioaddr + SIFADR); - - /* Read, invert and write */ - chk2 = inb(ioaddr + SIFADD); - chk2 ^= 0x0FE; - outb(chk2, ioaddr + SIFADR); - - /* Read, invert and compare */ - chk2 = inb(ioaddr + SIFADD); - chk2 ^= 0x0FE; - - if(chk1 != chk2) - return (-1); /* No adapter */ - - chk1 -= 2; - } while(chk1 != 0); /* Repeat 128 times (all byte values) */ - - /* Restore the SIFADR value */ - outb(old, ioaddr + SIFADR); - - return (0); -} - -/* * Open/initialize the board. This is called sometime after * booting when the 'ifconfig' program is run. * @@ -524,14 +253,14 @@ * registers that "should" only need to be set once at boot, so that * there is non-reboot way to recover if something goes wrong. */ -static int tms380tr_open(struct net_device *dev) +int tms380tr_open(struct net_device *dev) { struct net_local *tp = (struct net_local *)dev->priv; int err; /* Reset the hardware here. Don't forget to set the station address. */ err = tms380tr_chipset_init(dev); - if(err) + if(err) { printk(KERN_INFO "%s: Chipset initialization error\n", dev->name); @@ -548,7 +277,6 @@ printk(KERN_INFO "%s: Adapter RAM size: %dK\n", dev->name, tms380tr_read_ptr(dev)); - tms380tr_enable_interrupts(dev); tms380tr_open_adapter(dev); @@ -566,8 +294,8 @@ /* If AdapterVirtOpenFlag is 1, the adapter is now open for use */ if(tp->AdapterVirtOpenFlag == 0) { - tms380tr_disable_interrupts(dev); - return (-1); + tms380tr_disable_interrupts(dev); + return (-1); } dev->start = 1; @@ -579,10 +307,6 @@ tp->timer.function = tms380tr_timer_chk; tp->timer.data = (unsigned long)dev; add_timer(&tp->timer); - -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif return (0); } @@ -610,47 +334,20 @@ static int tms380tr_chipset_init(struct net_device *dev) { struct net_local *tp = (struct net_local *)dev->priv; - unsigned char PosReg, Tmp; - int i, err; + int err; tms380tr_init_ipb(tp); - tms380tr_init_opb(tp); + tms380tr_init_opb(dev); tms380tr_init_net_local(dev); - /* Set pos register: selects irq and dma channel. - * Only for ISA bus adapters. - */ - if(dev->dma > 0) - { - PosReg = 0; - for(i = 0; tms380tr_irqlist[i] != 0; i++) - { - if(tms380tr_irqlist[i] == dev->irq) - break; - } - - /* Choose default cycle time, 500 nsec */ - PosReg |= CYCLE_TIME << 2; - PosReg |= i << 4; - i = dev->dma - 5; - PosReg |= i; - - if(tp->DataRate == SPEED_4) - PosReg |= LINE_SPEED_BIT; - else - PosReg &= ~LINE_SPEED_BIT; - - outb(PosReg, dev->base_addr + POSREG); - Tmp = inb(dev->base_addr + POSREG); - if((Tmp & ~CYCLE_TIME) != (PosReg & ~CYCLE_TIME)) - printk(KERN_INFO "%s: POSREG error\n", dev->name); - } err = tms380tr_reset_adapter(dev); if(err < 0) return (-1); + err = tms380tr_bringup_diags(dev); if(err < 0) return (-1); + err = tms380tr_init_adapter(dev); if(err < 0) return (-1); @@ -690,7 +387,7 @@ skb_queue_head_init(&tp->SendSkbQueue); tp->QueueSkb = MAX_TX_QUEUE; - + /* Create circular chain of transmit lists */ for (i = 0; i < TPL_NUM; i++) { @@ -713,7 +410,7 @@ tp->Rpl[i].NextRPLAddr = htonl((unsigned long) virt_to_bus(&tp->Rpl[(i+1) % RPL_NUM])); tp->Rpl[i].Status = (RX_VALID | RX_START_FRAME | RX_END_FRAME | RX_FRAME_IRQ); tp->Rpl[i].FrameSize = 0; - tp->Rpl[i].FragList[0].DataCount = SWAPB(tp->MaxPacketSize); + tp->Rpl[i].FragList[0].DataCount = cpu_to_be16((unsigned short)tp->MaxPacketSize); /* Alloc skb and point adapter to data area */ tp->Rpl[i].Skb = dev_alloc_skb(tp->MaxPacketSize); @@ -731,7 +428,7 @@ skb_put(tp->Rpl[i].Skb, tp->MaxPacketSize); /* data unreachable for DMA ? then use local buffer */ - if(tp->CardType->type == TMS_ISA && virt_to_bus(tp->Rpl[i].Skb->data) + tp->MaxPacketSize > ISA_MAX_ADDRESS) + if(tp->dmalimit && virt_to_bus(tp->Rpl[i].Skb->data) + tp->MaxPacketSize > tp->dmalimit) { tp->Rpl[i].SkbStat = SKB_DATA_COPY; tp->Rpl[i].FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[i])); @@ -780,28 +477,37 @@ /* * Initializes the open parameter block. */ -static void tms380tr_init_opb(struct net_local *tp) +static void tms380tr_init_opb(struct net_device *dev) { + struct net_local *tp; unsigned long Addr; unsigned short RplSize = RPL_SIZE; unsigned short TplSize = TPL_SIZE; unsigned short BufferSize = BUFFER_SIZE; + int i; + + tp = (struct net_local *)dev->priv; tp->ocpl.OPENOptions = 0; tp->ocpl.OPENOptions |= ENABLE_FULL_DUPLEX_SELECTION; tp->ocpl.FullDuplex = 0; tp->ocpl.FullDuplex |= OPEN_FULL_DUPLEX_OFF; - /* Fixme: If mac address setable: - * for (i=0; iVam->ocpl.NodeAddr[i] = mac->CurrentAddress[i]; + /* + * Set node address + * + * We go ahead and put it in the OPB even though on + * most of the generic adapters this isn't required. + * Its simpler this way. -- ASF */ + for (i=0;i<6;i++) + tp->ocpl.NodeAddr[i] = ((unsigned char *)dev->dev_addr)[i]; tp->ocpl.GroupAddr = 0; tp->ocpl.FunctAddr = 0; - tp->ocpl.RxListSize = SWAPB(RplSize); - tp->ocpl.TxListSize = SWAPB(TplSize); - tp->ocpl.BufSize = SWAPB(BufferSize); + tp->ocpl.RxListSize = cpu_to_be16((unsigned short)RplSize); + tp->ocpl.TxListSize = cpu_to_be16((unsigned short)TplSize); + tp->ocpl.BufSize = cpu_to_be16((unsigned short)BufferSize); tp->ocpl.Reserved = 0; tp->ocpl.TXBufMin = TX_BUF_MIN; tp->ocpl.TXBufMax = TX_BUF_MAX; @@ -836,7 +542,7 @@ */ static void tms380tr_disable_interrupts(struct net_device *dev) { - outb(0, dev->base_addr + SIFACL); + SIFWRITEB(0, SIFACL); return; } @@ -847,7 +553,7 @@ */ static void tms380tr_enable_interrupts(struct net_device *dev) { - outb(ACL_SINTEN, dev->base_addr + SIFACL); + SIFWRITEB(ACL_SINTEN, SIFACL); return; } @@ -948,8 +654,7 @@ tp->QueueSkb++; /* Is buffer reachable for Busmaster-DMA? */ - if(tp->CardType->type == TMS_ISA && virt_to_bus((void*)(((long) skb->data) + skb->len)) - > ISA_MAX_ADDRESS) + if(tp->dmalimit && virt_to_bus((void*)(((long) skb->data) + skb->len)) > tp->dmalimit) { /* Copy frame to local buffer */ i = tp->TplFree->TPLIndex; @@ -975,11 +680,11 @@ /* Save the skb for delayed return of skb to system */ tpl->Skb = skb; - tpl->FragList[0].DataCount = (unsigned short) SWAPB(length); + tpl->FragList[0].DataCount = cpu_to_be16((unsigned short)length); tpl->FragList[0].DataAddr = htonl(virt_to_bus(newbuf)); /* Write the data length in the transmit list. */ - tpl->FrameSize = (unsigned short) SWAPB(length); + tpl->FrameSize = cpu_to_be16((unsigned short)length); tpl->MData = newbuf; /* Transmit the frame and set the status values. */ @@ -1057,48 +762,41 @@ /* * The typical workload of the driver: Handle the network interface interrupts. */ -static void tms380tr_interrupt(int irq, void *dev_id, struct pt_regs *regs) +void tms380tr_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; struct net_local *tp; - int ioaddr; unsigned short irq_type; - if(dev == NULL) - { + if(dev == NULL) { printk("%s: irq %d for unknown device.\n", dev->name, irq); return; } dev->interrupt = 1; - ioaddr = dev->base_addr; tp = (struct net_local *)dev->priv; - irq_type = inw(ioaddr + SIFSTS); + irq_type = SIFREADW(SIFSTS); - while(irq_type & STS_SYSTEM_IRQ) - { + while(irq_type & STS_SYSTEM_IRQ) { irq_type &= STS_IRQ_MASK; - if(!tms380tr_chk_ssb(tp, irq_type)) - { + if(!tms380tr_chk_ssb(tp, irq_type)) { printk(KERN_INFO "%s: DATA LATE occurred\n", dev->name); break; } - switch(irq_type) - { - case STS_IRQ_RECEIVE_STATUS: - tms380tr_reset_interrupt(dev); - tms380tr_rcv_status_irq(dev); - break; + switch(irq_type) { + case STS_IRQ_RECEIVE_STATUS: + tms380tr_reset_interrupt(dev); + tms380tr_rcv_status_irq(dev); + break; - case STS_IRQ_TRANSMIT_STATUS: - /* Check if TRANSMIT.HALT command is complete */ - if(tp->ssb.Parm[0] & COMMAND_COMPLETE) - { - tp->TransmitCommandActive = 0; + case STS_IRQ_TRANSMIT_STATUS: + /* Check if TRANSMIT.HALT command is complete */ + if(tp->ssb.Parm[0] & COMMAND_COMPLETE) { + tp->TransmitCommandActive = 0; tp->TransmitHaltScheduled = 0; /* Issue a new transmit command. */ @@ -1109,40 +807,51 @@ tms380tr_tx_status_irq(dev); break; - case STS_IRQ_COMMAND_STATUS: - /* The SSB contains status of last command - * other than receive/transmit. - */ - tms380tr_cmd_status_irq(dev); - break; - - case STS_IRQ_SCB_CLEAR: - /* The SCB is free for another command. */ - tp->ScbInUse = 0; - tms380tr_chk_outstanding_cmds(dev); - break; - - case STS_IRQ_RING_STATUS: - tms380tr_ring_status_irq(dev); - break; + case STS_IRQ_COMMAND_STATUS: + /* The SSB contains status of last command + * other than receive/transmit. + */ + tms380tr_cmd_status_irq(dev); + break; + + case STS_IRQ_SCB_CLEAR: + /* The SCB is free for another command. */ + tp->ScbInUse = 0; + tms380tr_chk_outstanding_cmds(dev); + break; + + case STS_IRQ_RING_STATUS: + tms380tr_ring_status_irq(dev); + break; - case STS_IRQ_ADAPTER_CHECK: - tms380tr_chk_irq(dev); - break; + case STS_IRQ_ADAPTER_CHECK: + tms380tr_chk_irq(dev); + break; - default: - printk(KERN_INFO "Unknown Token Ring IRQ\n"); - break; + case STS_IRQ_LLC_STATUS: + printk(KERN_DEBUG "tms380tr: unexpected LLC status IRQ\n"); + break; + + case STS_IRQ_TIMER: + printk(KERN_DEBUG "tms380tr: unexpected Timer IRQ\n"); + break; + + case STS_IRQ_RECEIVE_PENDING: + printk(KERN_DEBUG "tms380tr: unexpected Receive Pending IRQ\n"); + break; + + default: + printk(KERN_INFO "Unknown Token Ring IRQ (0x%04x)\n", irq_type); + break; } /* Reset system interrupt if not already done. */ if(irq_type != STS_IRQ_TRANSMIT_STATUS - && irq_type != STS_IRQ_RECEIVE_STATUS) - { + && irq_type != STS_IRQ_RECEIVE_STATUS) { tms380tr_reset_interrupt(dev); } - irq_type = inw(ioaddr + SIFSTS); + irq_type = SIFREADW(SIFSTS); } dev->interrupt = 0; @@ -1436,7 +1145,7 @@ /* * The inverse routine to tms380tr_open(). */ -static int tms380tr_close(struct net_device *dev) +int tms380tr_close(struct net_device *dev) { struct net_local *tp = (struct net_local *)dev->priv; dev->tbusy = 1; @@ -1469,13 +1178,9 @@ release_dma_lock(flags); } - outw(0xFF00, dev->base_addr + SIFCMD); - if(dev->dma > 0) - outb(0xff, dev->base_addr + POSREG); - -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif + SIFWRITEW(0xFF00, SIFCMD); + if(dev->dma > 0) /* what the? */ + SIFWRITEB(0xff, POSREG); tms380tr_cancel_tx_queue(tp); @@ -1549,7 +1254,7 @@ /* * Wait for some time (microseconds) */ -static void tms380tr_wait(unsigned long time) +void tms380tr_wait(unsigned long time) { #if 0 long tmp; @@ -1570,7 +1275,6 @@ */ static void tms380tr_exec_sifcmd(struct net_device *dev, unsigned int WriteValue) { - int ioaddr = dev->base_addr; unsigned short cmd; unsigned short SifStsValue; unsigned long loop_counter; @@ -1579,9 +1283,9 @@ cmd = (unsigned short)WriteValue; loop_counter = 0,5 * 800000; do { - SifStsValue = inw(ioaddr + SIFSTS); + SifStsValue = SIFREADW(SIFSTS); } while((SifStsValue & CMD_INTERRUPT_ADAPTER) && loop_counter--); - outw(cmd, ioaddr + SIFCMD); + SIFWRITEW(cmd, SIFCMD); return; } @@ -1595,22 +1299,19 @@ struct net_local *tp = (struct net_local *)dev->priv; unsigned short *fw_ptr = (unsigned short *)&tms380tr_code; unsigned short count, c; - int ioaddr = dev->base_addr; /* Hardware adapter reset */ - outw(ACL_ARESET, ioaddr + SIFACL); + SIFWRITEW(ACL_ARESET, SIFACL); tms380tr_wait(40); - c = inw(ioaddr + SIFACL); + c = SIFREADW(SIFACL); tms380tr_wait(20); if(dev->dma == 0) /* For PCI adapters */ { - c &= ~(ACL_SPEED4 | ACL_SPEED16); /* Clear bits */ - if(tp->DataRate == SPEED_4) - c |= ACL_SPEED4; /* Set 4Mbps */ - else - c |= ACL_SPEED16; /* Set 16Mbps */ + c &= ~(ACL_NSELOUT0 | ACL_NSELOUT1); /* Clear bits */ + if(tp->setnselout) + c |= (*tp->setnselout)(dev); } /* In case a command is pending - forget it */ @@ -1618,18 +1319,20 @@ c &= ~ACL_ARESET; /* Clear adapter reset bit */ c |= ACL_CPHALT; /* Halt adapter CPU, allow download */ + c |= ACL_BOOT; + c |= ACL_SINTEN; c &= ~ACL_PSDMAEN; /* Clear pseudo dma bit */ - outw(c, ioaddr + SIFACL); + SIFWRITEW(c, SIFACL); tms380tr_wait(40); /* Download firmware via DIO interface: */ do { /* Download first address part */ - outw(*fw_ptr, ioaddr + SIFADX); + SIFWRITEW(*fw_ptr, SIFADX); fw_ptr++; /* Download second address part */ - outw(*fw_ptr, ioaddr + SIFADD); + SIFWRITEW(*fw_ptr, SIFADD); fw_ptr++; if((count = *fw_ptr) != 0) /* Load loop counter */ @@ -1637,17 +1340,17 @@ fw_ptr++; /* Download block data */ for(; count > 0; count--) { - outw(*fw_ptr, ioaddr + SIFINC); + SIFWRITEW(*fw_ptr, SIFINC); fw_ptr++; } } else /* Stop, if last block downloaded */ { - c = inw(ioaddr + SIFACL); + c = SIFREADW(SIFACL); c &= (~ACL_CPHALT | ACL_SINTEN); /* Clear CPHALT and start BUD */ - outw(c, ioaddr + SIFACL); + SIFWRITEW(c, SIFACL); return (1); } } while(count == 0); @@ -1663,7 +1366,6 @@ { int loop_cnt, retry_cnt; unsigned short Status; - int ioaddr = dev->base_addr; tms380tr_wait(HALF_SECOND); tms380tr_exec_sifcmd(dev, EXEC_SOFT_RESET); @@ -1679,7 +1381,7 @@ do { /* Inspect BUD results */ loop_cnt--; tms380tr_wait(HALF_SECOND); - Status = inw(ioaddr + SIFSTS); + Status = SIFREADW(SIFSTS); Status &= STS_MASK; if(tms380tr_debug > 3) @@ -1701,11 +1403,16 @@ } } while(retry_cnt > 0); - Status = inw(ioaddr + SIFSTS); - Status &= STS_ERROR_MASK; /* Hardware error occurred! */ - - printk(KERN_INFO "%s: Bring Up Diagnostics Error (%04X) occurred\n", - dev->name, Status); + Status = SIFREADW(SIFSTS); + + /* Hardware error occurred! */ + Status &= 0x001f; + if (Status & 0x0010) + printk(KERN_INFO "%s: BUD Error: Timeout\n", dev->name); + else if ((Status & 0x000f) > 6) + printk(KERN_INFO "%s: BUD Error: Illegal Failure\n", dev->name); + else + printk(KERN_INFO "%s: Bring Up Diagnostics Error (%04X) occurred\n", dev->name, Status & 0x000f); return (-1); } @@ -1727,7 +1434,6 @@ unsigned char *sb_ptr = (unsigned char *) &tp->ssb; unsigned short Status; int i, loop_cnt, retry_cnt; - int ioaddr = dev->base_addr; /* Normalize: byte order low/high, word order high/low! (only IPB!) */ tp->ipb.SCB_Addr = SWAPW(virt_to_bus(&tp->scb)); @@ -1740,14 +1446,14 @@ retry_cnt--; /* Transfer initialization block */ - outw(0x0001, ioaddr + SIFADX); + SIFWRITEW(0x0001, SIFADX); /* To address 0001:0A00 of adapter RAM */ - outw(0x0A00, ioaddr + SIFADD); + SIFWRITEW(0x0A00, SIFADD); /* Write 11 words to adapter RAM */ for(i = 0; i < 11; i++) - outw(ipb_ptr[i], ioaddr + SIFINC); + SIFWRITEW(ipb_ptr[i], SIFINC); /* Execute SCB adapter command */ tms380tr_exec_sifcmd(dev, CMD_EXECUTE); @@ -1761,7 +1467,7 @@ tms380tr_wait(HALF_SECOND); /* Mask interesting status bits */ - Status = inw(ioaddr + SIFSTS); + Status = SIFREADW(SIFSTS); Status &= STS_MASK; } while(((Status &(STS_INITIALIZE | STS_ERROR | STS_TEST)) != 0) && ((Status & STS_ERROR) == 0) && (loop_cnt != 0)); @@ -1792,7 +1498,7 @@ if((Status & STS_ERROR) != 0) { /* Initialization error occurred */ - Status = inw(ioaddr + SIFSTS); + Status = SIFREADW(SIFSTS); Status &= STS_ERROR_MASK; /* ShowInitialisationErrorCode(Status); */ return (-1); /* Unrecoverable error */ @@ -1820,7 +1526,6 @@ { struct net_local *tp = (struct net_local *)dev->priv; unsigned long Addr = 0; - unsigned char i = 0; if(tp->CMDqueue == 0) return; /* No command execution */ @@ -1839,14 +1544,6 @@ /* Execute OPEN command */ tp->CMDqueue ^= OC_OPEN; - /* Copy the 18 bytes of the product ID */ - while((tp->CardType->name[i] != '\0') - && (i < PROD_ID_SIZE)) - { - tp->ProductID[i] = tp->CardType->name[i]; - i++; - } - Addr = htonl(virt_to_bus(&tp->ocpl)); tp->scb.Parm[0] = LOWORD(Addr); tp->scb.Parm[1] = HIWORD(Addr); @@ -2001,7 +1698,7 @@ { struct net_local *tp = (struct net_local *)dev->priv; - tp->CurrentRingStatus = SWAPB(tp->ssb.Parm[0]); + tp->CurrentRingStatus = be16_to_cpu((unsigned short)tp->ssb.Parm[0]); /* First: fill up statistics */ if(tp->ssb.Parm[0] & SIGNAL_LOSS) @@ -2071,19 +1768,18 @@ { int i; unsigned short AdapterCheckBlock[4]; - unsigned short ioaddr = dev->base_addr; struct net_local *tp = (struct net_local *)dev->priv; tp->AdapterOpenFlag = 0; /* Adapter closed now */ /* Page number of adapter memory */ - outw(0x0001, ioaddr + SIFADX); + SIFWRITEW(0x0001, SIFADX); /* Address offset */ - outw(CHECKADDR, ioaddr + SIFADR); + SIFWRITEW(CHECKADDR, SIFADR); /* Reading 8 byte adapter check block. */ for(i = 0; i < 4; i++) - AdapterCheckBlock[i] = inw(ioaddr + SIFINC); + AdapterCheckBlock[i] = SIFREADW(SIFINC); if(tms380tr_debug > 3) { @@ -2234,8 +1930,8 @@ tms380tr_read_ram(dev, (unsigned char *)&tp->intptrs.BurnedInAddrPtr, ADAPTER_INT_PTRS, 16); tms380tr_read_ram(dev, (unsigned char *)&adapterram, - (unsigned short)SWAPB(tp->intptrs.AdapterRAMPtr), 2); - return SWAPB(adapterram); + cpu_to_be16((unsigned short)tp->intptrs.AdapterRAMPtr), 2); + return be16_to_cpu(adapterram); } /* @@ -2246,22 +1942,21 @@ { int i; unsigned short old_sifadx, old_sifadr, InWord; - unsigned short ioaddr = dev->base_addr; /* Save the current values */ - old_sifadx = inw(ioaddr + SIFADX); - old_sifadr = inw(ioaddr + SIFADR); + old_sifadx = SIFREADW(SIFADX); + old_sifadr = SIFREADW(SIFADR); /* Page number of adapter memory */ - outw(0x0001, ioaddr + SIFADX); + SIFWRITEW(0x0001, SIFADX); /* Address offset in adapter RAM */ - outw(Address, ioaddr + SIFADR); + SIFWRITEW(Address, SIFADR); /* Copy len byte from adapter memory to system data area. */ i = 0; for(;;) { - InWord = inw(ioaddr + SIFINC); + InWord = SIFREADW(SIFINC); *(Data + i) = HIBYTE(InWord); /* Write first byte */ if(++i == Length) /* All is done break */ @@ -2273,30 +1968,8 @@ } /* Restore original values */ - outw(old_sifadx, ioaddr + SIFADX); - outw(old_sifadr, ioaddr + SIFADR); - - return; -} - -/* - * Reads MAC address from adapter ROM. - */ -static void tms380tr_read_addr(struct net_device *dev, unsigned char *Address) -{ - int i, In; - unsigned short ioaddr = dev->base_addr; - - /* Address: 0000:0000 */ - outw(0, ioaddr + SIFADX); - outw(0, ioaddr + SIFADR); - - /* Read six byte MAC address data */ - for(i = 0; i < 6; i++) - { - In = inw(ioaddr + SIFINC); - *(Address + i) = (unsigned char)(In >> 8); - } + SIFWRITEW(old_sifadx, SIFADX); + SIFWRITEW(old_sifadr, SIFADR); return; } @@ -2447,7 +2120,7 @@ /* Get the frame size (Byte swap for Intel). * Do this early (see workaround comment below) */ - Length = (unsigned short)SWAPB(rpl->FrameSize); + Length = be16_to_cpu((unsigned short)rpl->FrameSize); /* Check if the Frame_Start, Frame_End and * Frame_Complete bits are set. @@ -2463,15 +2136,16 @@ * Length2 is there because there have also been * cases where the FrameSize was partially written */ - Length2 = (unsigned short)SWAPB(rpl->FrameSize); + Length2 = be16_to_cpu((unsigned short)rpl->FrameSize); if(Length == 0 || Length != Length2) { tp->RplHead = SaveHead; break; /* Return to tms380tr_interrupt */ } -#if 0 /* This might happen for multicast or broadcast packets. - The upper layers are expected to handle this, not here */ +#if 0 /* This might happen for multicast or broadcast packets. + The upper layers are expected to handle this, not here */ + /* Drop frames sent by myself */ if(tms380tr_chk_frame(dev, rpl->MData)) { @@ -2552,8 +2226,7 @@ skb_put(rpl->Skb, tp->MaxPacketSize); /* Data unreachable for DMA ? then use local buffer */ - if(tp->CardType->type == TMS_ISA && virt_to_bus(rpl->Skb->data) + tp->MaxPacketSize - > ISA_MAX_ADDRESS) + if(tp->dmalimit && virt_to_bus(rpl->Skb->data) + tp->MaxPacketSize > tp->dmalimit) { rpl->SkbStat = SKB_DATA_COPY; rpl->FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[rpl->RPLIndex])); @@ -2568,7 +2241,7 @@ } } - rpl->FragList[0].DataCount = SWAPB(tp->MaxPacketSize); + rpl->FragList[0].DataCount = cpu_to_be16((unsigned short)tp->MaxPacketSize); rpl->FrameSize = 0; /* Pass the last RPL back to the adapter */ @@ -2619,6 +2292,7 @@ return; } +#if 0 /* * Check if it is a frame of myself. Compare source address with my current * address in reverse direction, and mask out the TR_RII. @@ -2639,6 +2313,20 @@ return (1); /* It is my frame. */ } +#endif + +static int tms380tr_set_mac_address(struct net_device *dev, void *addr) +{ + struct net_local *tp = (struct net_local *)dev->priv; + struct sockaddr *saddr = addr; + + if (tp->AdapterOpenFlag || tp->AdapterVirtOpenFlag) { + printk(KERN_WARNING "%s: Cannot set MAC/LAA address while card is open\n", dev->name); + return -EIO; + } + memcpy(dev->dev_addr, saddr->sa_data, dev->addr_len); + return 0; +} #if TMS380TR_DEBUG > 0 /* @@ -2651,80 +2339,73 @@ for (i = 0, j = 0; i < length / 8; i++, j += 8) { printk(KERN_DEBUG "%02x %02x %02x %02x %02x %02x %02x %02x\n", - Data[j+0],Data[j+1],Data[j+2],Data[j+3], - Data[j+4],Data[j+5],Data[j+6],Data[j+7]); + Data[j+0],Data[j+1],Data[j+2],Data[j+3], + Data[j+4],Data[j+5],Data[j+6],Data[j+7]); } return; } #endif -#ifdef MODULE +int tmsdev_init(struct net_device *dev) +{ + if (dev->priv == NULL) + { + struct net_local *tms_local; + + dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL | GFP_DMA); + if (dev->priv == NULL) + return -ENOMEM; + memset(dev->priv, 0, sizeof(struct net_local)); + tms_local = (struct net_local *)dev->priv; + init_waitqueue_head(&tms_local->wait_for_tok_int); + } + + /* These can be overridden by the card driver if needed */ + dev->init = tms380tr_init_card; + dev->open = tms380tr_open; + dev->stop = tms380tr_close; + dev->do_ioctl = NULL; + dev->hard_start_xmit = tms380tr_send_packet; + dev->get_stats = tms380tr_get_stats; + dev->set_multicast_list = &tms380tr_set_multicast_list; + dev->set_mac_address = tms380tr_set_mac_address; -static struct net_device* dev_tms380tr[TMS380TR_MAX_ADAPTERS]; -static int io[TMS380TR_MAX_ADAPTERS] = { 0, 0 }; -static int irq[TMS380TR_MAX_ADAPTERS] = { 0, 0 }; -static int mem[TMS380TR_MAX_ADAPTERS] = { 0, 0 }; - -MODULE_PARM(io, "1-" __MODULE_STRING(TMS380TR_MAX_ADAPTERS) "i"); -MODULE_PARM(irq, "1-" __MODULE_STRING(TMS380TR_MAX_ADAPTERS) "i"); -MODULE_PARM(mem, "1-" __MODULE_STRING(TMS380TR_MAX_ADAPTERS) "i"); + return 0; +} -int init_module(void) -{ - int i; +#ifdef MODULE - for(i = 0; i < TMS380TR_MAX_ADAPTERS; i++) - { - irq[i] = 0; - mem[i] = 0; - dev_tms380tr[i] = NULL; - dev_tms380tr[i] = init_trdev(dev_tms380tr[i], 0); - if(dev_tms380tr[i] == NULL) - return (-ENOMEM); - - dev_tms380tr[i]->base_addr = io[i]; - dev_tms380tr[i]->irq = irq[i]; - dev_tms380tr[i]->mem_start = mem[i]; - dev_tms380tr[i]->init = &tms380tr_probe; - - if(register_trdev(dev_tms380tr[i]) != 0) - { - kfree_s(dev_tms380tr[i], sizeof(struct net_device)); - dev_tms380tr[i] = NULL; - if(i == 0) - { - printk("tms380tr: register_trdev() returned non-zero.\n"); - return (-EIO); - } - else - return (0); - } +EXPORT_SYMBOL(tms380tr_open); +EXPORT_SYMBOL(tms380tr_close); +EXPORT_SYMBOL(tms380tr_interrupt); +EXPORT_SYMBOL(tmsdev_init); +EXPORT_SYMBOL(tms380tr_wait); - } +struct module *TMS380_module = NULL; - return (0); +int init_module(void) +{ + printk("%s", version); + + TMS380_module = &__this_module; + return 0; } void cleanup_module(void) { - int i; - - for(i = 0; i < TMS380TR_MAX_ADAPTERS; i++) - { - if(dev_tms380tr[i]) - { - unregister_trdev(dev_tms380tr[i]); - release_region(dev_tms380tr[i]->base_addr, TMS380TR_IO_EXTENT); - if(dev_tms380tr[i]->irq) - free_irq(dev_tms380tr[i]->irq, dev_tms380tr[i]); - if(dev_tms380tr[i]->dma > 0) - free_dma(dev_tms380tr[i]->dma); - if(dev_tms380tr[i]->priv) - kfree_s(dev_tms380tr[i]->priv, sizeof(struct net_local)); - kfree_s(dev_tms380tr[i], sizeof(struct net_device)); - dev_tms380tr[i] = NULL; - } - } + TMS380_module = NULL; } -#endif /* MODULE */ +#endif + + +/* + * Local variables: + * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c tms380tr.c" + * alt-compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c tms380tr.c" + * c-set-style "K&R" + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff -ru --new-file 2.3.40.clean/drivers/net/tokenring/tms380tr.h 2.3.40/drivers/net/tokenring/tms380tr.h --- 2.3.40.clean/drivers/net/tokenring/tms380tr.h Thu Oct 14 21:22:09 1999 +++ 2.3.40/drivers/net/tokenring/tms380tr.h Sun Jan 23 01:07:11 2000 @@ -1,7 +1,9 @@ -/* tms380tr.h: TI TMS380 Token Ring driver for Linux +/* + * tms380tr.h: TI TMS380 Token Ring driver for Linux * * Authors: * - Christoph Goos + * - Adam Fritzler */ #ifndef __LINUX_TMS380TR_H @@ -9,6 +11,13 @@ #ifdef __KERNEL__ +/* module prototypes */ +int tms380tr_open(struct net_device *dev); +int tms380tr_close(struct net_device *dev); +void tms380tr_interrupt(int irq, void *dev_id, struct pt_regs *regs); +int tmsdev_init(struct net_device *dev); +void tms380tr_wait(unsigned long time); + #define TMS380TR_MAX_ADAPTERS 7 #define SEND_TIMEOUT 10*HZ @@ -30,9 +39,6 @@ /* -------------------------------------------------------------- */ /*------------------------------------------------------------------*/ -/* Swap bytes of a word. */ -#define SWAPB(x) (((unsigned short)((x) << 8)) | ((unsigned short)((x) >> 8))) - /* Swap words of a long. */ #define SWAPW(x) (((x) << 16) | ((x) >> 16)) @@ -51,24 +57,34 @@ /* Token ring adapter I/O addresses for normal mode. */ -#define SIFDAT 0L /* SIF/DMA data. */ -#define SIFINC 2L /* IO Word data with auto increment. */ -#define SIFINH 3L /* IO Byte data with auto increment. */ -#define SIFADR 4L /* SIF/DMA Address. */ -#define SIFCMD 6L /* SIF Command. */ -#define SIFSTS 6L /* SIF Status. */ -#define SIFACL 8L /* SIF Adapter Control Register. */ -#define SIFADD 10L /* SIF/DMA Address. */ -#define SIFADX 12L -#define DMALEN 14L /* SIF DMA length. */ -#define POSREG 16L /* Adapter Program Option Select (POS) + +/* + * The SIF registers. Common to all adapters. + */ +/* Basic SIF (SRSX = 0) */ +#define SIFDAT 0x00 /* SIF/DMA data. */ +#define SIFINC 0x02 /* IO Word data with auto increment. */ +#define SIFINH 0x03 /* IO Byte data with auto increment. */ +#define SIFADR 0x04 /* SIF/DMA Address. */ +#define SIFCMD 0x06 /* SIF Command. */ +#define SIFSTS 0x06 /* SIF Status. */ + +/* "Extended" SIF (SRSX = 1) */ +#define SIFACL 0x08 /* SIF Adapter Control Register. */ +#define SIFADD 0x0a /* SIF/DMA Address. -- 0x0a */ +#define SIFADX 0x0c /* 0x0c */ +#define DMALEN 0x0e /* SIF DMA length. -- 0x0e */ + +/* + * POS Registers. Only for ISA Adapters. + */ +#define POSREG 0x10 /* Adapter Program Option Select (POS) * Register: base IO address + 16 byte. */ #define POSREG_2 24L /* only for TR4/16+ adapter - * base IO address + 24 byte. + * base IO address + 24 byte. -- 0x18 */ - /* SIFCMD command codes (high-low) */ #define CMD_INTERRUPT_ADAPTER 0x8000 /* Cause internal adapter interrupt */ #define CMD_ADAPTER_RESET 0x4000 /* Hardware reset of adapter */ @@ -118,8 +134,13 @@ * (1/0): can be written if ACL_ARESET * is zero. */ -#define ACL_SPEED4 0x0003 -#define ACL_SPEED16 0x0001 +#define ACL_PEN 0x0004 + +#define ACL_NSELOUT0 0x0002 +#define ACL_NSELOUT1 0x0001 /* NSELOUTx have a card-specific + * meaning for setting ring speed. + */ + #define PS_DMA_MASK (ACL_SWHRQ | ACL_PSDMAEN) @@ -145,69 +166,72 @@ /* Interrupt Codes (only MAC IRQs) */ -#define STS_IRQ_ADAPTER_CHECK 0x0000 /* unrecoverable hardware or +#define STS_IRQ_ADAPTER_CHECK 0x0000 /* unrecoverable hardware or * software error. */ -#define STS_IRQ_RING_STATUS 0x0004 /* SSB is updated with ring status. */ -#define STS_IRQ_SCB_CLEAR 0x0006 /* SCB clear, following an +#define STS_IRQ_RING_STATUS 0x0004 /* SSB is updated with ring status. */ +#define STS_IRQ_LLC_STATUS 0x0005 /* Not used in MAC-only microcode */ +#define STS_IRQ_SCB_CLEAR 0x0006 /* SCB clear, following an * SCB_REQUEST IRQ. */ -#define STS_IRQ_COMMAND_STATUS 0x0008 /* SSB is updated with command +#define STS_IRQ_TIMER 0x0007 /* Not normally used in MAC ucode */ +#define STS_IRQ_COMMAND_STATUS 0x0008 /* SSB is updated with command * status. */ -#define STS_IRQ_RECEIVE_STATUS 0x000A /* SSB is updated with receive +#define STS_IRQ_RECEIVE_STATUS 0x000A /* SSB is updated with receive * status. */ -#define STS_IRQ_TRANSMIT_STATUS 0x000C /* SSB is updated with transmit +#define STS_IRQ_TRANSMIT_STATUS 0x000C /* SSB is updated with transmit * status */ -#define STS_IRQ_MASK 0x000F /* = STS_ERROR_MASK. */ +#define STS_IRQ_RECEIVE_PENDING 0x000E /* Not used in MAC-only microcode */ +#define STS_IRQ_MASK 0x000F /* = STS_ERROR_MASK. */ /* TRANSMIT_STATUS completion code: (SSB.Parm[0]) */ -#define COMMAND_COMPLETE 0x0080 /* TRANSMIT command completed +#define COMMAND_COMPLETE 0x0080 /* TRANSMIT command completed * (avoid this!) issue another transmit * to send additional frames. */ -#define FRAME_COMPLETE 0x0040 /* Frame has been transmitted; +#define FRAME_COMPLETE 0x0040 /* Frame has been transmitted; * INTERRUPT_FRAME bit was set in the * CSTAT request; indication of possibly * more than one frame transmissions! * SSB.Parm[0-1]: 32 bit pointer to * TPL of last frame. */ -#define LIST_ERROR 0x0020 /* Error in one of the TPLs that +#define LIST_ERROR 0x0020 /* Error in one of the TPLs that * compose the frame; TRANSMIT - * terminated; Parm[1-2]: 32 bit pointer + * terminated; Parm[1-2]: 32bit pointer * to TPL which starts the error * frame; error details in bits 8-13. * (14?) */ -#define FRAME_SIZE_ERROR 0x8000 /* FRAME_SIZE does not equal the sum of +#define FRAME_SIZE_ERROR 0x8000 /* FRAME_SIZE does not equal the sum of * the valid DATA_COUNT fields; * FRAME_SIZE less than header plus * information field. (15 bytes + * routing field) Or if FRAME_SIZE * was specified as zero in one list. */ -#define TX_THRESHOLD 0x4000 /* FRAME_SIZE greater than (BUFFER_SIZE +#define TX_THRESHOLD 0x4000 /* FRAME_SIZE greater than (BUFFER_SIZE * - 9) * TX_BUF_MAX. */ -#define ODD_ADDRESS 0x2000 /* Odd forward pointer value is +#define ODD_ADDRESS 0x2000 /* Odd forward pointer value is * read on a list without END_FRAME * indication. */ -#define FRAME_ERROR 0x1000 /* START_FRAME bit is (not) anticipated, +#define FRAME_ERROR 0x1000 /* START_FRAME bit (not) anticipated, * but (not) set. */ -#define ACCESS_PRIORITY_ERROR 0x0800 /* Access priority requested has not +#define ACCESS_PRIORITY_ERROR 0x0800 /* Access priority requested has not * been allowed. */ -#define UNENABLED_MAC_FRAME 0x0400 /* MAC frame has source class of zero +#define UNENABLED_MAC_FRAME 0x0400 /* MAC frame has source class of zero * or MAC frame PCF ATTN field is * greater than one. */ -#define ILLEGAL_FRAME_FORMAT 0x0200 /* Bit 0 or FC field was set to one. */ +#define ILLEGAL_FRAME_FORMAT 0x0200 /* Bit 0 or FC field was set to one. */ /* @@ -222,98 +246,98 @@ * * The following defines the command code bits and the command queue: */ -#define OC_OPEN 0x0001 /* OPEN command */ -#define OC_TRANSMIT 0x0002 /* TRANSMIT command */ -#define OC_TRANSMIT_HALT 0x0004 /* TRANSMIT_HALT command */ -#define OC_RECEIVE 0x0008 /* RECEIVE command */ -#define OC_CLOSE 0x0010 /* CLOSE command */ -#define OC_SET_GROUP_ADDR 0x0020 /* SET_GROUP_ADDR command */ -#define OC_SET_FUNCT_ADDR 0x0040 /* SET_FUNCT_ADDR command */ -#define OC_READ_ERROR_LOG 0x0080 /* READ_ERROR_LOG command */ -#define OC_READ_ADAPTER 0x0100 /* READ_ADAPTER command */ -#define OC_MODIFY_OPEN_PARMS 0x0400 /* MODIFY_OPEN_PARMS command */ -#define OC_RESTORE_OPEN_PARMS 0x0800 /* RESTORE_OPEN_PARMS command */ -#define OC_SET_FIRST_16_GROUP 0x1000 /* SET_FIRST_16_GROUP command */ -#define OC_SET_BRIDGE_PARMS 0x2000 /* SET_BRIDGE_PARMS command */ -#define OC_CONFIG_BRIDGE_PARMS 0x4000 /* CONFIG_BRIDGE_PARMS command */ +#define OC_OPEN 0x0001 /* OPEN command */ +#define OC_TRANSMIT 0x0002 /* TRANSMIT command */ +#define OC_TRANSMIT_HALT 0x0004 /* TRANSMIT_HALT command */ +#define OC_RECEIVE 0x0008 /* RECEIVE command */ +#define OC_CLOSE 0x0010 /* CLOSE command */ +#define OC_SET_GROUP_ADDR 0x0020 /* SET_GROUP_ADDR command */ +#define OC_SET_FUNCT_ADDR 0x0040 /* SET_FUNCT_ADDR command */ +#define OC_READ_ERROR_LOG 0x0080 /* READ_ERROR_LOG command */ +#define OC_READ_ADAPTER 0x0100 /* READ_ADAPTER command */ +#define OC_MODIFY_OPEN_PARMS 0x0400 /* MODIFY_OPEN_PARMS command */ +#define OC_RESTORE_OPEN_PARMS 0x0800 /* RESTORE_OPEN_PARMS command */ +#define OC_SET_FIRST_16_GROUP 0x1000 /* SET_FIRST_16_GROUP command */ +#define OC_SET_BRIDGE_PARMS 0x2000 /* SET_BRIDGE_PARMS command */ +#define OC_CONFIG_BRIDGE_PARMS 0x4000 /* CONFIG_BRIDGE_PARMS command */ -#define OPEN 0x0300 /* C: open command. S: completion. */ -#define TRANSMIT 0x0400 /* C: transmit command. S: completion +#define OPEN 0x0300 /* C: open command. S: completion. */ +#define TRANSMIT 0x0400 /* C: transmit command. S: completion * status. (reject: COMMAND_REJECT if * adapter not opened, TRANSMIT already * issued or address passed in the SCB * not word aligned) */ -#define TRANSMIT_HALT 0x0500 /* C: interrupt TX TPL chain; if no +#define TRANSMIT_HALT 0x0500 /* C: interrupt TX TPL chain; if no * TRANSMIT command issued, the command - * is ignored. (completion with TRANSMIT + * is ignored (completion with TRANSMIT * status (0x0400)!) */ -#define RECEIVE 0x0600 /* C: receive command. S: completion +#define RECEIVE 0x0600 /* C: receive command. S: completion * status. (reject: COMMAND_REJECT if * adapter not opened, RECEIVE already * issued or address passed in the SCB * not word aligned) */ -#define CLOSE 0x0700 /* C: close adapter. S: completion. +#define CLOSE 0x0700 /* C: close adapter. S: completion. * (COMMAND_REJECT if adapter not open) */ -#define SET_GROUP_ADDR 0x0800 /* C: alter adapter group address after - * OPEN. S: completion. (COMMAND_REJECT +#define SET_GROUP_ADDR 0x0800 /* C: alter adapter group address after + * OPEN. S: completion. (COMMAND_REJECT * if adapter not open) */ -#define SET_FUNCT_ADDR 0x0900 /* C: alter adapter functional address +#define SET_FUNCT_ADDR 0x0900 /* C: alter adapter functional address * after OPEN. S: completion. * (COMMAND_REJECT if adapter not open) */ -#define READ_ERROR_LOG 0x0A00 /* C: read adapter error counters. +#define READ_ERROR_LOG 0x0A00 /* C: read adapter error counters. * S: completion. (command ignored * if adapter not open!) */ -#define READ_ADAPTER 0x0B00 /* C: read data from adapter memory. +#define READ_ADAPTER 0x0B00 /* C: read data from adapter memory. * (important: after init and before * open!) S: completion. (ADAPTER_CHECK * interrupt if undefined storage area * read) */ -#define MODIFY_OPEN_PARMS 0x0D00 /* C: modify some adapter operational +#define MODIFY_OPEN_PARMS 0x0D00 /* C: modify some adapter operational * parameters. (bit correspondend to * WRAP_INTERFACE is ignored) * S: completion. (reject: * COMMAND_REJECT) */ -#define RESTORE_OPEN_PARMS 0x0E00 /* C: modify some adapter operational +#define RESTORE_OPEN_PARMS 0x0E00 /* C: modify some adapter operational * parameters. (bit correspondend * to WRAP_INTERFACE is ignored) * S: completion. (reject: * COMMAND_REJECT) */ -#define SET_FIRST_16_GROUP 0x0F00 /* C: alter the first two bytes in +#define SET_FIRST_16_GROUP 0x0F00 /* C: alter the first two bytes in * adapter group address. * S: completion. (reject: * COMMAND_REJECT) */ -#define SET_BRIDGE_PARMS 0x1000 /* C: values and conditions for the +#define SET_BRIDGE_PARMS 0x1000 /* C: values and conditions for the * adapter hardware to use when frames * are copied for forwarding. * S: completion. (reject: * COMMAND_REJECT) */ -#define CONFIG_BRIDGE_PARMS 0x1100 /* C: .. +#define CONFIG_BRIDGE_PARMS 0x1100 /* C: .. * S: completion. (reject: * COMMAND_REJECT) */ -#define SPEED_4 4 -#define SPEED_16 16 /* Default transmission speed */ +#define SPEED_4 4 +#define SPEED_16 16 /* Default transmission speed */ /* Initialization Parameter Block (IPB); word alignment necessary! */ -#define BURST_SIZE 0x0018 /* Default burst size */ -#define BURST_MODE 0x9F00 /* Burst mode enable */ -#define DMA_RETRIES 0x0505 /* Magic DMA retry number... */ +#define BURST_SIZE 0x0018 /* Default burst size */ +#define BURST_MODE 0x9F00 /* Burst mode enable */ +#define DMA_RETRIES 0x0505 /* Magic DMA retry number... */ -#define CYCLE_TIME 3 /* Default AT-bus cycle time: 500 ns +#define CYCLE_TIME 3 /* Default AT-bus cycle time: 500 ns * (later adapter version: fix cycle time!) */ #define LINE_SPEED_BIT 0x80 @@ -327,7 +351,7 @@ #define FOUR_SECONDS (ONE_SECOND_TICKS * 4) #define FIVE_SECONDS (ONE_SECOND_TICKS * 5) -#define BUFFER_SIZE 2048 /* Buffers on Adapter */ +#define BUFFER_SIZE 2048 /* Buffers on Adapter */ #pragma pack(1) typedef struct { @@ -337,18 +361,18 @@ /* Interrupt vectors the adapter places on attached system bus. */ unsigned char CMD_Status_IV; /* Interrupt vector: command status. */ - unsigned char TX_IV; /* Interrupt vector: transmit. */ - unsigned char RX_IV; /* Interrupt vector: receive. */ + unsigned char TX_IV; /* Interrupt vector: transmit. */ + unsigned char RX_IV; /* Interrupt vector: receive. */ unsigned char Ring_Status_IV; /* Interrupt vector: ring status. */ - unsigned char SCB_Clear_IV; /* Interrupt vector: SCB clear. */ + unsigned char SCB_Clear_IV; /* Interrupt vector: SCB clear. */ unsigned char Adapter_CHK_IV; /* Interrupt vector: adapter check. */ unsigned short RX_Burst_Size; /* Max. number of transfer cycles. */ unsigned short TX_Burst_Size; /* During DMA burst; even value! */ - unsigned short DMA_Abort_Thrhld; /* Number of DMA retries. */ + unsigned short DMA_Abort_Thrhld;/* Number of DMA retries. */ - unsigned long SCB_Addr; /* SCB address: even, word aligned, high-low. */ - unsigned long SSB_Addr; /* SSB address: even, word aligned, high-low. */ + unsigned long SCB_Addr; /* SCB address: even, word aligned, high-low */ + unsigned long SSB_Addr; /* SSB address: even, word aligned, high-low */ } IPB, *IPB_Ptr; #pragma pack() @@ -361,10 +385,10 @@ #define RPL_SIZE 14 /* (with TI firmware v2.26 handling * up to nine fragments possible) */ -#define TX_BUF_MIN 20 /* ??? (Stephan: calculation with */ -#define TX_BUF_MAX 40 /* BUFFER_SIZE and MAX_FRAME_SIZE) ??? +#define TX_BUF_MIN 20 /* ??? (Stephan: calculation with */ +#define TX_BUF_MAX 40 /* BUFFER_SIZE and MAX_FRAME_SIZE) ??? */ -#define DISABLE_EARLY_TOKEN_RELEASE 0x1000 +#define DISABLE_EARLY_TOKEN_RELEASE 0x1000 /* OPEN Options (high-low) */ #define WRAP_INTERFACE 0x0080 /* Inserting omitted for test @@ -372,51 +396,52 @@ * as receive data. (usefull for * testing; change: CLOSE necessary) */ -#define DISABLE_HARD_ERROR 0x0040 /* On HARD_ERROR & TRANSMIT_BEACON +#define DISABLE_HARD_ERROR 0x0040 /* On HARD_ERROR & TRANSMIT_BEACON * no RING.STATUS interrupt. */ -#define DISABLE_SOFT_ERROR 0x0020 /* On SOFT_ERROR, no RING.STATUS +#define DISABLE_SOFT_ERROR 0x0020 /* On SOFT_ERROR, no RING.STATUS * interrupt. */ -#define PASS_ADAPTER_MAC_FRAMES 0x0010 /* Passing unsupported MAC frames +#define PASS_ADAPTER_MAC_FRAMES 0x0010 /* Passing unsupported MAC frames * to system. */ -#define PASS_ATTENTION_FRAMES 0x0008 /* All changed attention MAC frames are +#define PASS_ATTENTION_FRAMES 0x0008 /* All changed attention MAC frames are * passed to the system. */ -#define PAD_ROUTING_FIELD 0x0004 /* Routing field is padded to 18 +#define PAD_ROUTING_FIELD 0x0004 /* Routing field is padded to 18 * bytes. */ -#define FRAME_HOLD 0x0002 /* Adapter waits for entire frame before +#define FRAME_HOLD 0x0002 /*Adapter waits for entire frame before * initiating DMA transfer; otherwise: * DMA transfer initiation if internal * buffer filled. */ -#define CONTENDER 0x0001 /* Adapter participates in the monitor +#define CONTENDER 0x0001 /* Adapter participates in the monitor * contention process. */ -#define PASS_BEACON_MAC_FRAMES 0x8000 /* Adapter passes beacon MAC frames +#define PASS_BEACON_MAC_FRAMES 0x8000 /* Adapter passes beacon MAC frames * to the system. */ -#define EARLY_TOKEN_RELEASE 0x1000 /* Only valid in 16 Mbps operation; +#define EARLY_TOKEN_RELEASE 0x1000 /* Only valid in 16 Mbps operation; * 0 = ETR. (no effect in 4 Mbps * operation) */ -#define COPY_ALL_MAC_FRAMES 0x0400 /* All MAC frames are copied to +#define COPY_ALL_MAC_FRAMES 0x0400 /* All MAC frames are copied to * the system. (after OPEN: duplicate * address test (DAT) MAC frame is * first received frame copied to the * system) */ -#define COPY_ALL_NON_MAC_FRAMES 0x0200 /* All non MAC frames are copied to +#define COPY_ALL_NON_MAC_FRAMES 0x0200 /* All non MAC frames are copied to * the system. */ -#define PASS_FIRST_BUF_ONLY 0x0100 /* Passes only first internal buffer +#define PASS_FIRST_BUF_ONLY 0x0100 /* Passes only first internal buffer * of each received frame; FrameSize * of RPLs must contain internal * BUFFER_SIZE bits for promiscous mode. */ -#define ENABLE_FULL_DUPLEX_SELECTION 0x2000 /* Enable the use of full-duplex +#define ENABLE_FULL_DUPLEX_SELECTION 0x2000 + /* Enable the use of full-duplex * settings with bits in byte 22 in * ocpl. (new feature in firmware * version 3.09) @@ -434,7 +459,7 @@ * fragments following. */ -#define ISA_MAX_ADDRESS 0x00ffffff +#define ISA_MAX_ADDRESS 0x00ffffff #pragma pack(1) typedef struct { @@ -1031,15 +1056,6 @@ int RPLIndex; }; -#define TMS_ISA 1 -#define TMS_PCI 2 -struct cardinfo_table { - int type; /* 1 = ISA, 2 = PCI */ - int vendor_id; - int device_id; - char *name; -}; - /* Information that need to be kept for each board. */ typedef struct net_local { #pragma pack(1) @@ -1094,7 +1110,7 @@ struct tr_statistics MacStat; /* MAC statistics structure */ - struct cardinfo_table *CardType; + unsigned long dmalimit; /* the max DMA address (ie, ISA) */ struct timer_list timer; @@ -1103,6 +1119,13 @@ INTPTRS intptrs; /* Internal adapter pointer. Must be read * before OPEN command. */ + unsigned short (*setnselout)(struct net_device *); + unsigned short (*sifreadb)(struct net_device *, unsigned short); + void (*sifwriteb)(struct net_device *, unsigned short, unsigned short); + unsigned short (*sifreadw)(struct net_device *, unsigned short); + void (*sifwritew)(struct net_device *, unsigned short, unsigned short); + + void *tmspriv; } NET_LOCAL; #endif /* __KERNEL__ */ diff -ru --new-file 2.3.40.clean/drivers/net/tokenring/tmspci.c 2.3.40/drivers/net/tokenring/tmspci.c --- 2.3.40.clean/drivers/net/tokenring/tmspci.c Thu Jan 1 00:00:00 1970 +++ 2.3.40/drivers/net/tokenring/tmspci.c Sun Jan 23 01:07:11 2000 @@ -0,0 +1,336 @@ +/* + * tmspci.c: A generic network driver for TMS380-based PCI token ring cards. + * + * Written 1999 by Adam Fritzler + * + * This software may be used and distributed according to the terms + * of the GNU Public License, incorporated herein by reference. + * + * This driver module supports the following cards: + * - SysKonnect TR4/16(+) PCI (SK-4590) + * - SysKonnect TR4/16 PCI (SK-4591) + * - Compaq TR 4/16 PCI + * - Thomas-Conrad TC4048 4/16 PCI + * - 3Com 3C339 Token Link Velocity + * + * Maintainer(s): + * AF Adam Fritzler mid@auk.cx + * + * Modification History: + * 30-Dec-99 AF Split off from the tms380tr driver. + * 22-Jan-00 AF Updated to use indirect read/writes + * + * TODO: + * 1. See if we can use MMIO instead of port accesses + * + */ +static const char *version = "tmspci.c: v1.01 22/01/2000 by Adam Fritzler\n"; + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include "tms380tr.h" + +#define TMS_PCI_IO_EXTENT 32 + +struct cardinfo_table { + int vendor_id; /* PCI info */ + int device_id; + int registeroffset; /* SIF offset from dev->base_addr */ + unsigned char nselout[2]; /* NSELOUT vals for 4mb([0]) and 16mb([1]) */ + char *name; +}; + +struct cardinfo_table probelist[] = { + { 0, 0, + 0x0000, {0x00, 0x00}, "Unknown TMS380 Token Ring Adapter"}, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TOKENRING, + 0x0000, {0x03, 0x01}, "Compaq 4/16 TR PCI"}, + { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_TR, + 0x0000, {0x03, 0x01}, "SK NET TR 4/16 PCI"}, + { PCI_VENDOR_ID_TCONRAD, PCI_DEVICE_ID_TCONRAD_TOKENRING, + 0x0000, {0x03, 0x01}, "Thomas-Conrad TC4048 PCI 4/16"}, + { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C339, + 0x0000, {0x03, 0x01}, "3Com Token Link Velocity"}, + { 0, 0, 0, {0x00, 0x00}, NULL} +}; + +int tms_pci_probe(void); +static int tms_pci_open(struct net_device *dev); +static int tms_pci_close(struct net_device *dev); +static void tms_pci_read_eeprom(struct net_device *dev); +static unsigned short tms_pci_setnselout_pins(struct net_device *dev); + +static unsigned short tms_pci_sifreadb(struct net_device *dev, unsigned short reg) +{ + return inb(dev->base_addr + reg); +} + +static unsigned short tms_pci_sifreadw(struct net_device *dev, unsigned short reg) +{ + return inw(dev->base_addr + reg); +} + +static void tms_pci_sifwriteb(struct net_device *dev, unsigned short val, unsigned short reg) +{ + outb(val, dev->base_addr + reg); +} + +static void tms_pci_sifwritew(struct net_device *dev, unsigned short val, unsigned short reg) +{ + outw(val, dev->base_addr + reg); +} + +struct tms_pci_card { + struct net_device *dev; + struct pci_dev *pci_dev; + struct cardinfo_table *cardinfo; + struct tms_pci_card *next; +}; +static struct tms_pci_card *tms_pci_card_list = NULL; + + +struct cardinfo_table * __init tms_pci_getcardinfo(unsigned short vendor, + unsigned short device) +{ + int cur; + for (cur = 1; probelist[cur].name != NULL; cur++) { + if ((probelist[cur].vendor_id == vendor) && + (probelist[cur].device_id == device)) + return &probelist[cur]; + } + + return NULL; +} + +int __init tms_pci_probe(void) +{ + static int versionprinted = 0; + struct pci_dev *pdev = NULL ; + struct net_device *dev; + struct net_local *tp; + int i; + + if (!pci_present()) + return (-1); /* No PCI present. */ + + while ( (pdev=pci_find_class(PCI_CLASS_NETWORK_TOKEN_RING<<8, pdev))) { + unsigned int pci_irq_line; + unsigned long pci_ioaddr; + struct tms_pci_card *card; + struct cardinfo_table *cardinfo; + + if ((cardinfo = + tms_pci_getcardinfo(pdev->vendor, pdev->device)) == NULL) + continue; + + if (versionprinted++ == 0) + printk("%s", version); + + pci_enable_device(pdev); + + /* Remove I/O space marker in bit 0. */ + pci_irq_line = pdev->irq; + pci_ioaddr = pdev->resource[0].start ; + + if(check_region(pci_ioaddr, TMS_PCI_IO_EXTENT)) + continue; + + /* At this point we have found a valid card. */ + + dev = init_trdev(NULL, 0); + + request_region(pci_ioaddr, TMS_PCI_IO_EXTENT, cardinfo->name); + if(request_irq(pdev->irq, tms380tr_interrupt, SA_SHIRQ, + cardinfo->name, dev)) { + release_region(pci_ioaddr, TMS_PCI_IO_EXTENT); + continue; /*return (-ENODEV);*/ /* continue; ?? */ + } + + /* + if (load_tms380_module("tmspci.c")) { + return 0; + } + */ + + pci_ioaddr &= ~3 ; + dev->base_addr = pci_ioaddr; + dev->irq = pci_irq_line; + dev->dma = 0; + + printk("%s: %s\n", dev->name, cardinfo->name); + printk("%s: IO: %#4lx IRQ: %d\n", + dev->name, dev->base_addr, dev->irq); + /* + * Some cards have their TMS SIF registers offset from + * their given base address. Account for that here. + */ + dev->base_addr += cardinfo->registeroffset; + + tms_pci_read_eeprom(dev); + + printk("%s: Ring Station Address: ", dev->name); + printk("%2.2x", dev->dev_addr[0]); + for (i = 1; i < 6; i++) + printk(":%2.2x", dev->dev_addr[i]); + printk("\n"); + + if (tmsdev_init(dev)) { + printk("%s: unable to get memory for dev->priv.\n", dev->name); + return 0; + } + + tp = (struct net_local *)dev->priv; + tp->dmalimit = 0; /* XXX: should be the max PCI32 DMA max */ + tp->setnselout = tms_pci_setnselout_pins; + + tp->sifreadb = tms_pci_sifreadb; + tp->sifreadw = tms_pci_sifreadw; + tp->sifwriteb = tms_pci_sifwriteb; + tp->sifwritew = tms_pci_sifwritew; + + memcpy(tp->ProductID, cardinfo->name, PROD_ID_SIZE + 1); + + tp->tmspriv = cardinfo; + + dev->open = tms_pci_open; + dev->stop = tms_pci_close; + + if (register_trdev(dev) == 0) { + /* Enlist in the card list */ + card = kmalloc(sizeof(struct tms_pci_card), GFP_KERNEL); + card->next = tms_pci_card_list; + tms_pci_card_list = card; + card->dev = dev; + card->pci_dev = pdev; + card->cardinfo = cardinfo; + } else { + printk("%s: register_trdev() returned non-zero.\n", dev->name); + kfree(dev->priv); + kfree(dev); + return -1; + } + } + + if (tms_pci_card_list) + return 0; + return (-1); +} + +/* + * Reads MAC address from adapter RAM, which should've read it from + * the onboard ROM. + * + * Calling this on a board that does not support it can be a very + * dangerous thing. The Madge board, for instance, will lock your + * machine hard when this is called. Luckily, its supported in a + * seperate driver. --ASF + */ +static void tms_pci_read_eeprom(struct net_device *dev) +{ + int i; + + /* Address: 0000:0000 */ + tms_pci_sifwritew(dev, 0, SIFADX); + tms_pci_sifwritew(dev, 0, SIFADR); + + /* Read six byte MAC address data */ + dev->addr_len = 6; + for(i = 0; i < 6; i++) + dev->dev_addr[i] = tms_pci_sifreadw(dev, SIFINC) >> 8; +} + +unsigned short tms_pci_setnselout_pins(struct net_device *dev) +{ + unsigned short val = 0; + struct net_local *tp = (struct net_local *)dev->priv; + struct cardinfo_table *cardinfo = (struct cardinfo_table *)tp->tmspriv; + + if(tp->DataRate == SPEED_4) + val |= cardinfo->nselout[0]; /* Set 4Mbps */ + else + val |= cardinfo->nselout[1]; /* Set 16Mbps */ + return val; +} + +static int tms_pci_open(struct net_device *dev) +{ + tms380tr_open(dev); + MOD_INC_USE_COUNT; + return 0; +} + +static int tms_pci_close(struct net_device *dev) +{ + tms380tr_close(dev); + MOD_DEC_USE_COUNT; + return 0; +} + +#ifdef MODULE + +int init_module(void) +{ + /* Probe for cards. */ + if (tms_pci_probe()) { + printk(KERN_NOTICE "tmspci.c: No cards found.\n"); + } + /* lock_tms380_module(); */ + return (0); +} + +void cleanup_module(void) +{ + struct net_device *dev; + struct tms_pci_card *this_card; + + while (tms_pci_card_list) { + dev = tms_pci_card_list->dev; + + /* + * If we used a register offset, revert here. + */ + if (dev->priv) + { + struct net_local *tp; + struct cardinfo_table *cardinfo; + + tp = (struct net_local *)dev->priv; + cardinfo = (struct cardinfo_table *)tp->tmspriv; + + dev->base_addr -= cardinfo->registeroffset; + } + unregister_netdev(dev); + release_region(dev->base_addr, TMS_PCI_IO_EXTENT); + free_irq(dev->irq, dev); + kfree(dev->priv); + kfree(dev); + this_card = tms_pci_card_list; + tms_pci_card_list = this_card->next; + kfree(this_card); + } + /* unlock_tms380_module(); */ +} +#endif /* MODULE */ + + +/* + * Local variables: + * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c tmspci.c" + * alt-compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c tmspci.c" + * c-set-style "K&R" + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff -ru --new-file 2.3.40.clean/drivers/scsi/aha1542.c 2.3.40/drivers/scsi/aha1542.c --- 2.3.40.clean/drivers/scsi/aha1542.c Thu Dec 30 01:00:54 1999 +++ 2.3.40/drivers/scsi/aha1542.c Sun Jan 23 01:07:11 2000 @@ -21,6 +21,8 @@ * Modified by Chris Faulhaber * Added module command-line options * 19-Jul-99 + * Modified by Adam Fritzler + * Added proper detection of the AHA-1640 (MCA version of AHA-1540) */ #include @@ -40,6 +42,9 @@ #include #include #include +#ifdef CONFIG_MCA +#include +#endif #include "scsi.h" #include "hosts.h" @@ -96,7 +101,7 @@ #define MAXBOARDS 4 /* Increase this and the sizes of the arrays below, if you need more.. */ -/* Boards 3,4 slots are reserved for ISAPnP scans */ +/* Boards 3,4 slots are reserved for ISAPnP/MCA scans */ static unsigned int bases[MAXBOARDS] = {0x330, 0x334, 0, 0}; @@ -1043,6 +1048,69 @@ setup_dmaspeed[0] = atbt; } #endif + + /* + * Find MicroChannel cards (AHA1640) + */ +#ifdef CONFIG_MCA + if(MCA_bus) { + int slot = 0; + int pos = 0; + + for (indx = 0; (slot != MCA_NOTFOUND) && + (indx < sizeof(bases)/sizeof(bases[0])); indx++) { + + if (bases[indx]) + continue; + + /* Detect only AHA-1640 cards -- MCA ID 0F1F */ + slot = mca_find_unused_adapter(0x0f1f, slot); + if (slot == MCA_NOTFOUND) + break; + + + /* Found one */ + pos = mca_read_stored_pos(slot, 3); + + /* Decode address */ + if (pos & 0x80) { + if (pos & 0x02) { + if (pos & 0x01) + bases[indx] = 0x334; + else + bases[indx] = 0x234; + } else { + if (pos & 0x01) + bases[indx] = 0x134; + } + } else { + if (pos & 0x02) { + if (pos & 0x01) + bases[indx] = 0x330; + else + bases[indx] = 0x230; + } else { + if (pos & 0x01) + bases[indx] = 0x130; + } + } + + /* No need to decode IRQ and Arb level -- those are + * read off the card later. + */ + printk(KERN_INFO "Found an AHA-1640 in MCA slot %d, I/O 0x%04x\n", slot, bases[indx]); + + mca_set_adapter_name(slot, "Adapter AHA-1640"); + mca_set_adapter_procfn(slot, NULL, NULL); + mca_mark_as_used(slot); + + /* Go on */ + slot++; + } + + } +#endif + /* * Hunt for ISA Plug'n'Pray Adaptecs (AHA1535) */ diff -ru --new-file 2.3.40.clean/net/ipv4/ipconfig.c 2.3.40/net/ipv4/ipconfig.c --- 2.3.40.clean/net/ipv4/ipconfig.c Sun Jan 9 05:36:20 2000 +++ 2.3.40/net/ipv4/ipconfig.c Sun Jan 23 01:07:11 2000 @@ -534,7 +534,14 @@ /* Construct BOOTP header */ b->op = BOOTP_REQUEST; - b->htype = dev->type; + if (dev->type < 256) /* check for false types */ + b->htype = dev->type; + else if (dev->type == ARPHRD_IEEE802_TR) /* fix for token ring */ + b->htype = ARPHRD_IEEE802; + else { + printk("Unknown ARP type 0x%04x for device %s\n", dev->type, dev->name); + b->htype = dev->type; /* can cause undefined behavior */ + } b->hlen = dev->addr_len; memcpy(b->hw_addr, dev->dev_addr, dev->addr_len); b->secs = htons(jiffies / HZ);