diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-02-18 22:06:10 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-02-18 22:06:10 +0000 |
commit | aba4e552a2f2c1492441acbccedd8e0a4c53f916 (patch) | |
tree | 23921efb2b4af590160f034a89ff3da2ecca6e47 /drivers/net | |
parent | 9e17e1aa1cf1cb497d2f67147a51831888affcf3 (diff) |
Merge with Linux 2.3.43.
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/Makefile | 4 | ||||
-rw-r--r-- | drivers/net/Space.c | 21 | ||||
-rw-r--r-- | drivers/net/cs89x0.h | 8 | ||||
-rw-r--r-- | drivers/net/daynaport.c | 451 | ||||
-rw-r--r-- | drivers/net/irda/Config.in | 10 | ||||
-rw-r--r-- | drivers/net/irda/Makefile | 12 | ||||
-rw-r--r-- | drivers/net/irda/airport.c | 358 | ||||
-rw-r--r-- | drivers/net/irda/irport.c | 61 | ||||
-rw-r--r-- | drivers/net/irda/irtty.c | 10 | ||||
-rw-r--r-- | drivers/net/irda/nsc-ircc.c (renamed from drivers/net/irda/nsc_fir.c) | 1018 | ||||
-rw-r--r-- | drivers/net/irda/smc-ircc.c | 699 | ||||
-rw-r--r-- | drivers/net/irda/toshoboe.c | 46 | ||||
-rw-r--r-- | drivers/net/irda/w83977af_ir.c | 51 | ||||
-rw-r--r-- | drivers/net/mac89x0.c | 678 | ||||
-rw-r--r-- | drivers/net/macmace.c | 825 | ||||
-rw-r--r-- | drivers/net/macsonic.c | 834 | ||||
-rw-r--r-- | drivers/net/sun3lance.c | 21 | ||||
-rw-r--r-- | drivers/net/sunbmac.c | 2 | ||||
-rw-r--r-- | drivers/net/sunhme.c | 2 | ||||
-rw-r--r-- | drivers/net/sunlance.c | 2 | ||||
-rw-r--r-- | drivers/net/sunqe.c | 2 |
21 files changed, 3492 insertions, 1623 deletions
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 03864c4ba..232075634 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -115,7 +115,7 @@ obj-$(CONFIG_NET) += Space.o setup.o net_init.o loopback.o obj-$(CONFIG_SEEQ8005) += seeq8005.o obj-$(CONFIG_ETHERTAP) += ethertap.o obj-$(CONFIG_NET_SB1000) += sb1000.o -obj-$(CONFIG_DAYNAPORT) += daynaport.o 8390.o +obj-$(CONFIG_MAC8390) += daynaport.o 8390.o obj-$(CONFIG_APNE) += apne.o 8390.o obj-$(CONFIG_PCMCIA_PCNET) += 8390.o obj-$(CONFIG_SHAPER) += shaper.o @@ -248,6 +248,8 @@ obj-$(CONFIG_IPDDP) += ipddp.o obj-$(CONFIG_RCPCI) += rcpci.o obj-$(CONFIG_MACE) += mace.o obj-$(CONFIG_MACSONIC) += macsonic.o +obj-$(CONFIG_MACMACE) += macmace.o +obj-$(CONFIG_MAC89x0) += mac89x0.o obj-$(CONFIG_BMAC) += bmac.o obj-$(CONFIG_NCR885E) += ncr885e.o obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o diff --git a/drivers/net/Space.c b/drivers/net/Space.c index dc18256ce..52c3a23d0 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -106,7 +106,13 @@ extern int dec_lance_probe(struct net_device *); extern int mvme147lance_probe(struct net_device *dev); extern int tc515_probe(struct net_device *dev); extern int lance_probe(struct net_device *dev); -extern int mac_onboard_sonic_probe(struct net_device *dev); +extern int mace68k_probe(struct net_device *dev); +extern int macsonic_probe(struct net_device *dev); +extern int mac8390_probe(struct net_device *dev); +extern int mac89x0_probe(struct net_device *dev); + + /* Gigabit Ethernet adapters */ + extern int yellowfin_probe(struct net_device *dev); /* Detachable devices ("pocket adaptors") */ extern int atp_init(struct net_device *); @@ -356,8 +362,17 @@ struct devprobe m68k_probes[] __initdata = { #ifdef CONFIG_MVME147_NET /* MVME147 internal Ethernet */ {mvme147lance_probe, 0}, #endif -#ifdef CONFIG_MACSONIC /* Mac 68k Quadra builtin Ethernet */ - {mac_onboard_sonic_probe, 0}, +#ifdef CONFIG_MACMACE /* Mac 68k Quadra AV builtin Ethernet */ + {mace68k_probe, 0}, +#endif +#ifdef CONFIG_MACSONIC /* Mac SONIC-based Ethernet of all sorts */ + {macsonic_probe, 0}, +#endif +#ifdef CONFIG_MAC8390 /* NuBus NS8390-based cards */ + {mac8390_probe, 0}, +#endif +#ifdef CONFIG_MAC89x0 + {mac89x0_probe, 0}, #endif {NULL, 0}, }; diff --git a/drivers/net/cs89x0.h b/drivers/net/cs89x0.h index 42776088f..7e78805af 100644 --- a/drivers/net/cs89x0.h +++ b/drivers/net/cs89x0.h @@ -14,6 +14,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include <linux/config.h> + #define PP_ChipID 0x0000 /* offset 0h -> Corp -ID */ /* offset 2h -> Model/Product Number */ /* offset 3h -> Chip Revision Number */ @@ -77,6 +79,12 @@ #define ADD_MASK 0x3000 /* Mask it use of the ADD_PORT register */ #define ADD_SIG 0x3000 /* Expected ID signature */ +/* On Macs, we only need use the ISA I/O stuff until we do MEMORY_ON */ +#ifdef CONFIG_MAC +#define LCSLOTBASE 0xfee00000 +#define MMIOBASE 0x40000 +#endif + #define CHIP_EISA_ID_SIG 0x630E /* Product ID Code for Crystal Chip (CS8900 spec 4.3) */ #ifdef IBMEIPKT diff --git a/drivers/net/daynaport.c b/drivers/net/daynaport.c index 02ebff8b6..724369bb8 100644 --- a/drivers/net/daynaport.c +++ b/drivers/net/daynaport.c @@ -1,4 +1,4 @@ -/* mac_ns8390.c: A Macintosh 8390 based ethernet driver for linux. */ +/* daynaport.c: A Macintosh 8390 based ethernet driver for linux. */ /* Derived from code: @@ -15,14 +15,20 @@ The block output routines may be wrong for non Dayna cards - Reading MAC addresses -*/ + Fix this driver so that it will attempt to use the info + (i.e. iobase, iosize) given to it by the new and improved + NuBus code. + + Despite its misleading filename, this driver is not Dayna-specific + anymore. */ +/* Cabletron E6100 card support added by Tony Mantler (eek@escape.ca) April 1999 */ static const char *version = - "mac_ns8390.c:v0.01 7/5/97 Alan Cox (Alan.Cox@linux.org)\n"; + "daynaport.c: v0.02 1999-05-17 Alan Cox (Alan.Cox@linux.org) and others\n"; +static int version_printed = 0; #include <linux/module.h> - +#include <linux/init.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/errno.h> @@ -31,20 +37,26 @@ static const char *version = #include <asm/io.h> #include <asm/system.h> #include <asm/hwtest.h> +#include <asm/macints.h> #include <linux/delay.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include "8390.h" -int ns8390_probe1(struct net_device *dev, int word16, char *name, int id, int prom); +extern int console_loglevel; + +int ns8390_probe1(struct net_device *dev, int word16, char *name, int id, + int prom, struct nubus_dev *ndev); static int ns8390_open(struct net_device *dev); static void ns8390_no_reset(struct net_device *dev); static int ns8390_close_card(struct net_device *dev); +/* Interlan */ static void interlan_reset(struct net_device *dev); +/* Dayna */ static void dayna_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page); static void dayna_block_input(struct net_device *dev, int count, @@ -52,6 +64,7 @@ static void dayna_block_input(struct net_device *dev, int count, static void dayna_block_output(struct net_device *dev, int count, const unsigned char *buf, const int start_page); +/* Sane (32-bit chunk memory read/write) */ static void sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page); static void sane_block_input(struct net_device *dev, int count, @@ -59,6 +72,7 @@ static void sane_block_input(struct net_device *dev, int count, static void sane_block_output(struct net_device *dev, int count, const unsigned char *buf, const int start_page); +/* Slow Sane (16-bit chunk memory read/write) */ static void slow_sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page); static void slow_sane_block_input(struct net_device *dev, int count, @@ -71,6 +85,10 @@ static void slow_sane_block_output(struct net_device *dev, int count, #define WD03_STOP_PG 0x20 /* Last page +1 of RX ring */ #define WD13_STOP_PG 0x40 /* Last page +1 of RX ring */ +#define CABLETRON_RX_START_PG 0x00 /* First page of RX buffer */ +#define CABLETRON_RX_STOP_PG 0x30 /* Last page +1 of RX ring */ +#define CABLETRON_TX_START_PG CABLETRON_RX_STOP_PG /* First page of TX buffer */ + #define DAYNA_MAC_BASE 0xf0007 #define DAYNA_8390_BASE 0x80000 /* 3 */ @@ -81,9 +99,14 @@ static void slow_sane_block_output(struct net_device *dev, int count, #define APPLE_8390_MEM 0xD0000 #define APPLE_MEMSIZE 8192 /* FIXME: need to dynamically check */ -#define KINETICS_8390_BASE 0x80003 -#define KINETICS_8390_MEM 0x00000 +#define KINETICS_MAC_BASE 0xf0004 /* first byte of each long */ +#define KINETICS_8390_BASE 0x80000 +#define KINETICS_8390_MEM 0x00000 /* first word of each long */ #define KINETICS_MEMSIZE 8192 /* FIXME: need to dynamically check */ +/*#define KINETICS_MEMSIZE (0x10000/2) * CSA: on the board I have, at least */ + +#define CABLETRON_8390_BASE 0x90000 +#define CABLETRON_8390_MEM 0x00000 static int test_8390(volatile char *ptr, int scale) { @@ -113,34 +136,59 @@ static int test_8390(volatile char *ptr, int scale) * Identify the species of NS8390 card/driver we need */ -#define NS8390_DAYNA 1 -#define NS8390_INTERLAN 2 -#define NS8390_KINETICS 3 -#define NS8390_APPLE 4 -#define NS8390_FARALLON 5 -#define NS8390_ASANTE 6 +enum mac8390_type { + NS8390_DAYNA, + NS8390_INTERLAN, + NS8390_KINETICS, + NS8390_APPLE, + NS8390_FARALLON, + NS8390_ASANTE, + NS8390_CABLETRON +}; -int ns8390_ident(struct nubus_type *nb) +int __init ns8390_ident(struct nubus_dev* ndev) { - /* It appears anything with a software type of 0 is an apple - compatible - even if the hardware matches others */ - - if(nb->DrSW==0x0001 || nb->DrSW==0x0109 || nb->DrSW==0x0000 || nb->DrSW==0x0100) - return NS8390_APPLE; - + /* This really needs to be tested and tested hard. */ + + /* Summary of what we know so far -- + * SW: 0x0104 -- asante, 16 bit, back4_offsets + * SW: 0x010b -- daynaport, 16 bit, fwrd4_offsets + * SW: 0x010c -- farallon, 16 bit, back4_offsets, no long word access + * SW: 0x011a -- focus, [no details yet] + * SW: ?????? -- interlan, 16 bit, back4_offsets, funny reset + * SW: ?????? -- kinetics, 8 bit, back4_offsets + * -- so i've this hypothesis going that says DrSW&1 says whether the + * map is forward or backwards -- and maybe DrSW&256 says what the + * register spacing is -- for all cards that report a DrSW in some + * range. + * This would allow the "apple compatible" driver to drive many + * seemingly different types of cards. More DrSW info is needed + * to investigate this properly. [CSA, 21-May-1999] + */ /* Dayna ex Kinetics board */ - if(nb->DrHW==0x0103) + if(ndev->dr_sw == NUBUS_DRSW_DAYNA) return NS8390_DAYNA; - - /* Asante board */ - if(nb->DrHW==0x0104) + if(ndev->dr_sw == NUBUS_DRSW_ASANTE) return NS8390_ASANTE; - if(nb->DrHW==0x0100) - return NS8390_INTERLAN; - if(nb->DrHW==0x0106) - return NS8390_KINETICS; - if(nb->DrSW==0x010C) + if(ndev->dr_sw == NUBUS_DRSW_FARALLON) /* farallon or sonic systems */ return NS8390_FARALLON; + if(ndev->dr_sw == NUBUS_DRSW_KINETICS) + return NS8390_KINETICS; + /* My ATI Engineering card with this combination crashes the */ + /* driver trying to xmit packets. Best not touch it for now. */ + /* - 1999-05-20 (funaho@jurai.org) */ + if(ndev->dr_sw == NUBUS_DRSW_FOCUS) + return -1; + + /* Check the HW on this one, because it shares the same DrSW as + the on-board SONIC chips */ + if(ndev->dr_hw == NUBUS_DRHW_CABLETRON) + return NS8390_CABLETRON; + /* does anyone have one of these? */ + if(ndev->dr_hw == NUBUS_DRHW_INTERLAN) + return NS8390_INTERLAN; + + /* FIXME: what do genuine Apple boards look like? */ return -1; } @@ -148,7 +196,7 @@ int ns8390_ident(struct nubus_type *nb) * Memory probe for 8390 cards */ -int apple_8390_mem_probe(volatile unsigned short *p) +int __init apple_8390_mem_probe(volatile unsigned short *p) { int i, j; /* @@ -192,61 +240,79 @@ int apple_8390_mem_probe(volatile unsigned short *p) /* * Probe for 8390 cards. * The ns8390_probe1() routine initializes the card and fills the - * station address field. On entry base_addr is set, irq is set - * (These come from the nubus probe code). dev->mem_start points + * station address field. + * + * The NuBus interface has changed! We now scan for these somewhat + * like how the PCI and Zorro drivers do. It's not clear whether + * this is actually better, but it makes things more consistent. + * + * dev->mem_start points * at the memory ring, dev->mem_end gives the end of it. */ -int ns8390_probe(struct nubus_device_specifier *d, int slot, struct nubus_type *match) +int __init mac8390_probe(struct net_device *dev) { - struct net_device *dev; + static int slots = 0; volatile unsigned short *i; volatile unsigned char *p; int plen; int id; + static struct nubus_dev* ndev = NULL; + + /* Find the first card that hasn't already been seen */ + while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, + NUBUS_TYPE_ETHERNET, ndev)) != NULL) { + /* Have we seen it already? */ + if (slots & (1<<ndev->board->slot)) + continue; + slots |= 1<<ndev->board->slot; + + /* Is it one of ours? */ + if ((id = ns8390_ident(ndev)) != -1) + break; + } - if(match->category!=NUBUS_CAT_NETWORK || match->type!=1) - return -ENODEV; - /* Ok so it is an ethernet network device */ - if((id=ns8390_ident(match))==-1) - { - printk("Ethernet but type unknown %d\n",match->DrHW); + /* Hm. No more cards, then */ + if (ndev == NULL) return -ENODEV; + + dev = init_etherdev(dev, 0); + + if (!version_printed) { + printk(KERN_INFO "%s", version); + version_printed = 1; } - dev = init_etherdev(0, 0); - if(dev==NULL) - return -ENOMEM; /* * Dayna specific init */ if(id==NS8390_DAYNA) { - dev->base_addr=(int)(nubus_slot_addr(slot)+DAYNA_8390_BASE); - dev->mem_start=(int)(nubus_slot_addr(slot)+DAYNA_8390_MEM); - dev->mem_end=dev->mem_start+DAYNA_MEMSIZE; /* 8K it seems */ + dev->base_addr = (int)(ndev->board->slot_addr+DAYNA_8390_BASE); + dev->mem_start = (int)(ndev->board->slot_addr+DAYNA_8390_MEM); + dev->mem_end = dev->mem_start+DAYNA_MEMSIZE; /* 8K it seems */ - printk("daynaport: testing board: "); - + printk(KERN_INFO "%s: daynaport. testing board: ", dev->name); + printk("memory - "); - - i=(void *)dev->mem_start; + + i = (void *)dev->mem_start; memset((void *)i,0xAA, DAYNA_MEMSIZE); while(i<(volatile unsigned short *)dev->mem_end) { if(*i!=0xAAAA) goto membad; - *i=0x5555; - if(*i!=0x5555) + *i=0x5678; /* make sure we catch byte smearing */ + if(*i!=0x5678) goto membad; i+=2; /* Skip a word */ } - + printk("controller - "); - + p=(void *)dev->base_addr; plen=0; - + while(plen<0x3FF00) { if(test_8390(p,0)==0) @@ -263,26 +329,71 @@ int ns8390_probe(struct nubus_device_specifier *d, int slot, struct nubus_type * if(plen==0x3FF00) goto membad; printk("OK\n"); - dev->irq=slot; - if(ns8390_probe1(dev, 0, "dayna", id, -1)==0) - return 0; + dev->irq = SLOT2IRQ(ndev->board->slot); + if(ns8390_probe1(dev, 0, "dayna", id, -1, ndev)==0) + return 0; + } + /* Cabletron */ + if (id==NS8390_CABLETRON) { + int memsize = 16<<10; /* fix this */ + + dev->base_addr=(int)(ndev->board->slot_addr+CABLETRON_8390_BASE); + dev->mem_start=(int)(ndev->board->slot_addr+CABLETRON_8390_MEM); + dev->mem_end=dev->mem_start+memsize; + dev->irq = SLOT2IRQ(ndev->board->slot); + + /* The base address is unreadable if 0x00 has been written to the command register */ + /* Reset the chip by writing E8390_NODMA+E8390_PAGE0+E8390_STOP just to be sure */ + i = (void *)dev->base_addr; + *i = 0x21; + + printk(KERN_INFO "%s: cabletron: testing board: ", dev->name); + printk("%dK memory - ", memsize>>10); + i=(void *)dev->mem_start; + while(i<(volatile unsigned short *)(dev->mem_start+memsize)) + { + *i=0xAAAA; + if(*i!=0xAAAA) + goto membad; + *i=0x5555; + if(*i!=0x5555) + goto membad; + i+=2; /* Skip a word */ + } + printk("OK\n"); + + if(ns8390_probe1(dev, 1, "cabletron", id, -1, ndev)==0) + return 0; } /* Apple, Farallon, Asante */ - if(id==NS8390_APPLE|| id==NS8390_FARALLON || id==NS8390_ASANTE) + if(id==NS8390_APPLE || id==NS8390_FARALLON || id==NS8390_ASANTE) { int memsize; - - dev->base_addr=(int)(nubus_slot_addr(slot)+APPLE_8390_BASE); - dev->mem_start=(int)(nubus_slot_addr(slot)+APPLE_8390_MEM); - + + dev->base_addr=(int)(ndev->board->slot_addr+APPLE_8390_BASE); + dev->mem_start=(int)(ndev->board->slot_addr+APPLE_8390_MEM); + memsize = apple_8390_mem_probe((void *)dev->mem_start); - + dev->mem_end=dev->mem_start+memsize; - dev->irq=slot; - printk("apple/clone: testing board: "); - + dev->irq = SLOT2IRQ(ndev->board->slot); + + switch(id) + { + case NS8390_FARALLON: + printk(KERN_INFO "%s: farallon: testing board: ", dev->name); + break; + case NS8390_ASANTE: + printk(KERN_INFO "%s: asante: testing board: ", dev->name); + break; + case NS8390_APPLE: + default: + printk(KERN_INFO "%s: apple/clone: testing board: ", dev->name); + break; + } + printk("%dK memory - ", memsize>>10); - + i=(void *)dev->mem_start; memset((void *)i,0xAA, memsize); while(i<(volatile unsigned short *)dev->mem_end) @@ -295,51 +406,75 @@ int ns8390_probe(struct nubus_device_specifier *d, int slot, struct nubus_type * i+=2; /* Skip a word */ } printk("OK\n"); - - if(id==NS8390_FARALLON) + + switch (id) { - if(ns8390_probe1(dev, 1, "farallon", id, -1)==0) + case NS8390_FARALLON: + if(ns8390_probe1(dev, 1, "farallon", id, -1, ndev)==0) return 0; - } - else - { - if(ns8390_probe1(dev, 1, "apple/clone", id, -1)==0) - return 0; + break; + case NS8390_ASANTE: + if(ns8390_probe1(dev, 1, "asante", id, -1, ndev)==0) + return 0; + break; + case NS8390_APPLE: + default: + if(ns8390_probe1(dev, 1, "apple/clone", id, -1, ndev)==0) + return 0; + break; } } /* Interlan */ if(id==NS8390_INTERLAN) { /* As apple and asante */ - dev->base_addr=(int)(nubus_slot_addr(slot)+APPLE_8390_BASE); - dev->mem_start=(int)(nubus_slot_addr(slot)+APPLE_8390_MEM); + dev->base_addr=(int)(ndev->board->slot_addr+APPLE_8390_BASE); + dev->mem_start=(int)(ndev->board->slot_addr+APPLE_8390_MEM); dev->mem_end=dev->mem_start+APPLE_MEMSIZE; /* 8K it seems */ - dev->irq=slot; - if(ns8390_probe1(dev, 1, "interlan", id, -1)==0) + dev->irq = SLOT2IRQ(ndev->board->slot); + if(ns8390_probe1(dev, 1, "interlan", id, -1, ndev)==0) return 0; } - /* Kinetics */ + /* Kinetics (Shiva Etherport) */ if(id==NS8390_KINETICS) { - dev->base_addr=(int)(nubus_slot_addr(slot)+KINETICS_8390_BASE); - dev->mem_start=(int)(nubus_slot_addr(slot)+KINETICS_8390_MEM); + dev->base_addr=(int)(ndev->board->slot_addr+KINETICS_8390_BASE); + dev->mem_start=(int)(ndev->board->slot_addr+KINETICS_8390_MEM); dev->mem_end=dev->mem_start+KINETICS_MEMSIZE; /* 8K it seems */ - dev->irq=slot; - if(ns8390_probe1(dev, 0, "kinetics", id, -1)==0) + dev->irq = SLOT2IRQ(ndev->board->slot); + if(ns8390_probe1(dev, 0, "kinetics", id, -1, ndev)==0) return 0; } - kfree(dev); + + /* We should hopefully not get here */ + printk(KERN_ERR "Probe unsucessful.\n"); return -ENODEV; -membad: - printk("failed.\n"); - kfree(dev); + + membad: + printk(KERN_ERR "failed at %p in %p - %p.\n", i, + (void *)dev->mem_start, (void *)dev->mem_end); return -ENODEV; } -int ns8390_probe1(struct net_device *dev, int word16, char *model_name, int type, int promoff) +int __init mac8390_ethernet_addr(struct nubus_dev* ndev, + unsigned char addr[6]) { - static unsigned version_printed = 0; + struct nubus_dir dir; + struct nubus_dirent ent; + + /* Get the functional resource for this device */ + if (nubus_get_func_dir(ndev, &dir) == -1) + return -1; + if (nubus_find_rsrc(&dir, NUBUS_RESID_MAC_ADDRESS, &ent) == -1) + return -1; + + nubus_get_rsrc_mem(addr, &ent, 6); + return 0; +} +int __init ns8390_probe1(struct net_device *dev, int word16, char *model_name, + int type, int promoff, struct nubus_dev *ndev) +{ static u32 fwrd4_offsets[16]={ 0, 4, 8, 12, 16, 20, 24, 28, @@ -352,25 +487,19 @@ int ns8390_probe1(struct net_device *dev, int word16, char *model_name, int type 28, 24, 20, 16, 12, 8, 4, 0 }; + static u32 fwrd2_offsets[16]={ + 0, 2, 4, 6, + 8, 10, 12, 14, + 16, 18, 20, 22, + 24, 26, 28, 30 + }; - unsigned char *prom=((unsigned char *)nubus_slot_addr(dev->irq))+promoff; + unsigned char *prom = (unsigned char*) ndev->board->slot_addr + promoff; - if (ei_debug && version_printed++ == 0) - printk(version); - - /* Snarf the interrupt now. There's no point in waiting since we cannot - share a slot! and the board will usually be enabled. */ - if (nubus_request_irq(dev->irq, dev, ei_interrupt)) - { - printk (" unable to get nubus IRQ %d.\n", dev->irq); - return EAGAIN; - } - /* Allocate dev->priv and fill in 8390 specific dev fields. */ if (ethdev_init(dev)) { - printk (" unable to get memory for dev->priv.\n"); - nubus_free_irq(dev->irq); + printk ("%s: unable to get memory for dev->priv.\n", dev->name); return -ENOMEM; } @@ -378,16 +507,25 @@ int ns8390_probe1(struct net_device *dev, int word16, char *model_name, int type ei_status.name = model_name; ei_status.word16 = word16; - ei_status.tx_start_page = WD_START_PG; - ei_status.rx_start_page = WD_START_PG + TX_PAGES; - dev->rmem_start = dev->mem_start + TX_PAGES*256; - ei_status.stop_page = (dev->mem_end - dev->mem_start)/256; - dev->rmem_end = dev->mem_end; + if (type==NS8390_CABLETRON) { + /* Cabletron card puts the RX buffer before the TX buffer */ + ei_status.tx_start_page = CABLETRON_TX_START_PG; + ei_status.rx_start_page = CABLETRON_RX_START_PG; + ei_status.stop_page = CABLETRON_RX_STOP_PG; + dev->rmem_start = dev->mem_start; + dev->rmem_end = dev->mem_start + CABLETRON_RX_STOP_PG*256; + } else { + ei_status.tx_start_page = WD_START_PG; + ei_status.rx_start_page = WD_START_PG + TX_PAGES; + ei_status.stop_page = (dev->mem_end - dev->mem_start)/256; + dev->rmem_start = dev->mem_start + TX_PAGES*256; + dev->rmem_end = dev->mem_end; + } if(promoff==-1) /* Use nubus resources ? */ { - if(nubus_ethernet_addr(dev->irq /* slot */, dev->dev_addr)) + if(mac8390_ethernet_addr(ndev, dev->dev_addr)) { printk("mac_ns8390: MAC address not in resources!\n"); return -ENODEV; @@ -400,7 +538,7 @@ int ns8390_probe1(struct net_device *dev, int word16, char *model_name, int type /* These should go in the end I hope */ if(type==NS8390_DAYNA) x=2; - if(type==NS8390_INTERLAN) + if(type==NS8390_INTERLAN || type==NS8390_KINETICS) x=4; while(i<6) { @@ -412,12 +550,24 @@ int ns8390_probe1(struct net_device *dev, int word16, char *model_name, int type } } - printk(" %s, IRQ %d, shared memory at %#lx-%#lx.\n", - model_name, dev->irq, dev->mem_start, dev->mem_end-1); + printk(KERN_INFO "%s: %s in slot %X (type %s)\n", + dev->name, ndev->board->name, ndev->board->slot, model_name); + printk(KERN_INFO "MAC "); + { + int i; + for (i = 0; i < 6; i++) { + printk("%2.2x", dev->dev_addr[i]); + if (i < 5) + printk(":"); + } + } + printk(" IRQ %d, shared memory at %#lx-%#lx.\n", + dev->irq, dev->mem_start, dev->mem_end-1); switch(type) { case NS8390_DAYNA: /* Dayna card */ + case NS8390_KINETICS: /* Kinetics -- 8 bit config, but 16 bit mem */ /* 16 bit, 4 word offsets */ ei_status.reset_8390 = &ns8390_no_reset; ei_status.block_input = &dayna_block_input; @@ -425,6 +575,15 @@ int ns8390_probe1(struct net_device *dev, int word16, char *model_name, int type ei_status.get_8390_hdr = &dayna_get_8390_hdr; ei_status.reg_offset = fwrd4_offsets; break; + case NS8390_CABLETRON: /* Cabletron */ + /* 16 bit card, register map is short forward */ + ei_status.reset_8390 = &ns8390_no_reset; + /* Ctron card won't accept 32bit values read or written to it */ + ei_status.block_input = &slow_sane_block_input; + ei_status.block_output = &slow_sane_block_output; + ei_status.get_8390_hdr = &slow_sane_get_8390_hdr; + ei_status.reg_offset = fwrd2_offsets; + break; case NS8390_FARALLON: case NS8390_APPLE: /* Apple/Asante/Farallon */ /* 16 bit card, register map is reversed */ @@ -450,6 +609,8 @@ int ns8390_probe1(struct net_device *dev, int word16, char *model_name, int type ei_status.get_8390_hdr = &sane_get_8390_hdr; ei_status.reg_offset = back4_offsets; break; +#if 0 /* i think this suffered code rot. my kinetics card has much + * different settings. -- CSA [22-May-1999] */ case NS8390_KINETICS: /* Kinetics */ /* 8bit card, map is forward */ ei_status.reset_8390 = &ns8390_no_reset; @@ -458,6 +619,7 @@ int ns8390_probe1(struct net_device *dev, int word16, char *model_name, int type ei_status.get_8390_hdr = &sane_get_8390_hdr; ei_status.reg_offset = back4_offsets; break; +#endif default: panic("Detected a card I can't drive - whoops\n"); } @@ -472,6 +634,19 @@ int ns8390_probe1(struct net_device *dev, int word16, char *model_name, int type static int ns8390_open(struct net_device *dev) { ei_open(dev); + + /* At least on my card (a Focus Enhancements PDS card) I start */ + /* getting interrupts right away, so the driver needs to be */ + /* completely initialized before enabling the interrupt. */ + /* - funaho@jurai.org (1999-05-17) */ + + /* Non-slow interrupt, works around issues with the SONIC driver */ + if (request_irq(dev->irq, ei_interrupt, 0, "8390 Ethernet", dev)) + { + printk ("%s: unable to get IRQ %d.\n", dev->name, dev->irq); + return EAGAIN; + } + MOD_INC_USE_COUNT; return 0; } @@ -489,24 +664,19 @@ static int ns8390_close_card(struct net_device *dev) { if (ei_debug > 1) printk("%s: Shutting down ethercard.\n", dev->name); + free_irq(dev->irq, dev); ei_close(dev); MOD_DEC_USE_COUNT; return 0; } -struct nubus_device_specifier nubus_8390={ - ns8390_probe, - NULL -}; - - /* * Interlan Specific Code Starts Here */ static void interlan_reset(struct net_device *dev) { - unsigned char *target=nubus_slot_addr(dev->irq); + unsigned char *target=nubus_slot_addr(IRQ2SLOT(dev->irq)); if (ei_debug > 1) printk("Need to reset the NS8390 t=%lu...", jiffies); ei_status.txing = 0; @@ -531,16 +701,23 @@ static void interlan_reset(struct net_device *dev) The only complications are that the ring buffer wraps. */ -static void dayna_cpu_memcpy(struct net_device *dev, void *to, int from, int count) +static void dayna_memcpy_fromcard(struct net_device *dev, void *to, int from, int count) { volatile unsigned short *ptr; unsigned short *target=to; from<<=1; /* word, skip overhead */ ptr=(unsigned short *)(dev->mem_start+from); + /* + * Leading byte? + */ + if (from&2) { + *((char *)target)++ = *(((char *)ptr++)-1); + count--; + } while(count>=2) { *target++=*ptr++; /* Copy and */ - ptr++; /* Cruft and */ + ptr++; /* skip cruft */ count-=2; } /* @@ -554,16 +731,24 @@ static void dayna_cpu_memcpy(struct net_device *dev, void *to, int from, int cou } } -static void cpu_dayna_memcpy(struct net_device *dev, int to, const void *from, int count) +static void dayna_memcpy_tocard(struct net_device *dev, int to, const void *from, int count) { volatile unsigned short *ptr; const unsigned short *src=from; to<<=1; /* word, skip overhead */ ptr=(unsigned short *)(dev->mem_start+to); + /* + * Leading byte? + */ + if (to&2) { /* avoid a byte write (stomps on other data) */ + ptr[-1] = (ptr[-1]&0xFF00)|*((unsigned char *)src)++; + ptr++; + count--; + } while(count>=2) { *ptr++=*src++; /* Copy and */ - ptr++; /* Cruft and */ + ptr++; /* skip cruft */ count-=2; } /* @@ -573,14 +758,15 @@ static void cpu_dayna_memcpy(struct net_device *dev, int to, const void *from, i { /* Big endian */ unsigned short v=*src; - *((char *)ptr)=v>>8; + /* card doesn't like byte writes */ + *ptr=(*ptr&0x00FF)|(v&0xFF00); } } static void dayna_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) { unsigned long hdr_start = (ring_page - WD_START_PG)<<8; - dayna_cpu_memcpy(dev, (void *)hdr, hdr_start, 4); + dayna_memcpy_fromcard(dev, (void *)hdr, hdr_start, 4); /* Register endianism - fix here rather than 8390.c */ hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8); } @@ -599,14 +785,14 @@ static void dayna_block_input(struct net_device *dev, int count, struct sk_buff { /* We must wrap the input move. */ int semi_count = dev->rmem_end - xfer_start; - dayna_cpu_memcpy(dev, skb->data, xfer_base, semi_count); + dayna_memcpy_fromcard(dev, skb->data, xfer_base, semi_count); count -= semi_count; - dayna_cpu_memcpy(dev, skb->data + semi_count, + dayna_memcpy_fromcard(dev, skb->data + semi_count, dev->rmem_start - dev->mem_start, count); } else { - dayna_cpu_memcpy(dev, skb->data, xfer_base, count); + dayna_memcpy_fromcard(dev, skb->data, xfer_base, count); } } @@ -615,7 +801,7 @@ static void dayna_block_output(struct net_device *dev, int count, const unsigned { long shmem = (start_page - WD_START_PG)<<8; - cpu_dayna_memcpy(dev, shmem, buf, count); + dayna_memcpy_tocard(dev, shmem, buf, count); } /* @@ -739,6 +925,7 @@ static void slow_sane_block_output(struct net_device *dev, int count, const unsi * Local variables: * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c daynaport.c" * version-control: t + * c-basic-offset: 4 * tab-width: 4 * kept-new-versions: 5 * End: diff --git a/drivers/net/irda/Config.in b/drivers/net/irda/Config.in index da1df253c..da0b5f4be 100644 --- a/drivers/net/irda/Config.in +++ b/drivers/net/irda/Config.in @@ -6,10 +6,12 @@ dep_tristate 'IrTTY (uses Linux serial driver)' CONFIG_IRTTY_SIR $CONFIG_IRDA dep_tristate 'IrPORT (IrDA serial driver)' CONFIG_IRPORT_SIR $CONFIG_IRDA comment 'FIR device drivers' -dep_tristate 'NSC PC87108/PC97338' CONFIG_NSC_FIR $CONFIG_IRDA +dep_tristate 'NSC PC87108/PC87338' CONFIG_NSC_FIR $CONFIG_IRDA dep_tristate 'Winbond W83977AF (IR)' CONFIG_WINBOND_FIR $CONFIG_IRDA dep_tristate 'Toshiba Type-O IR Port' CONFIG_TOSHIBA_FIR $CONFIG_IRDA -dep_tristate 'SMC IrCC' CONFIG_SMC_IRCC_FIR $CONFIG_IRDA +if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then +dep_tristate 'SMC IrCC (Experimental)' CONFIG_SMC_IRCC_FIR $CONFIG_IRDA +fi comment 'Dongle support' bool 'Serial dongle support' CONFIG_DONGLE @@ -19,9 +21,7 @@ if [ "$CONFIG_DONGLE" != "n" ]; then dep_tristate ' Tekram IrMate 210B dongle' CONFIG_TEKRAM_DONGLE $CONFIG_IRDA dep_tristate ' Greenwich GIrBIL dongle' CONFIG_GIRBIL_DONGLE $CONFIG_IRDA dep_tristate ' Parallax LiteLink dongle' CONFIG_LITELINK_DONGLE $CONFIG_IRDA - dep_tristate ' Adaptec Airport 1000/2000 dongle' CONFIG_AIRPORT_DONGLE $CONFIG_IRDA - dep_tristate ' Old Belkin dongle' CONFIG_OLD_BELKIN_DONGLE $CONFIG_IRDA - + dep_tristate ' Old Belkin dongle' CONFIG_OLD_BELKIN_DONGLE $CONFIG_IRDA fi endmenu diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile index bf5628ebd..291a27f05 100644 --- a/drivers/net/irda/Makefile +++ b/drivers/net/irda/Makefile @@ -29,10 +29,10 @@ else endif ifeq ($(CONFIG_NSC_FIR),y) -L_OBJS += nsc_fir.o +L_OBJS += nsc-ircc.o else ifeq ($(CONFIG_NSC_FIR),m) - M_OBJS += nsc_fir.o + M_OBJS += nsc-ircc.o endif endif @@ -118,14 +118,6 @@ else endif endif -ifeq ($(CONFIG_AIRPORT_DONGLE),y) -L_OBJS += airport.o -else - ifeq ($(CONFIG_AIRPORT_DONGLE),m) - M_OBJS += airport.o - endif -endif - ifeq ($(CONFIG_OLD_BELKIN_DONGLE),y) L_OBJS += old_belkin.o else diff --git a/drivers/net/irda/airport.c b/drivers/net/irda/airport.c deleted file mode 100644 index b68378189..000000000 --- a/drivers/net/irda/airport.c +++ /dev/null @@ -1,358 +0,0 @@ -/********************************************************************* - * - * Filename: airport.c - * Version: 0.2 - * Description: Implementation for the Adaptec Airport 1000 and 2000 - * dongles - * Status: Experimental. - * Author: Fons Botman <budely@tref.nl> - * Created at: Wed May 19 23:14:34 CEST 1999 - * Based on: actisys.c by Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-1999 Fons Botman, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * Neither Fons Botman nor anyone else admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/tty.h> -#include <linux/sched.h> -#include <linux/init.h> - -#include <net/irda/irda.h> -#include <net/irda/irmod.h> -#include <net/irda/irda_device.h> - -static int airport_reset_wrapper(struct irda_task *task); -static void airport_open(dongle_t *self, struct qos_info *qos); -static void airport_close(dongle_t *self); -static int airport_change_speed_wrapper(struct irda_task *task); - -static struct dongle_reg dongle = { - Q_NULL, - IRDA_AIRPORT_DONGLE, - airport_open, - airport_close, - airport_reset_wrapper, - airport_change_speed_wrapper, -}; - -int __init airport_init(void) -{ - int ret; - - IRDA_DEBUG(2, __FUNCTION__ "()\n"); - ret = irda_device_register_dongle(&dongle); - if (ret < 0) - return ret; - return 0; -} - -void airport_cleanup(void) -{ - IRDA_DEBUG(2, __FUNCTION__ "()\n"); - irda_device_unregister_dongle(&dongle); -} - -static void airport_open(dongle_t *self, struct qos_info *qos) -{ - qos->baud_rate.bits &= - IR_2400|IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; - /* May need 1ms */ - qos->min_turn_time.bits = 0x07; - - MOD_INC_USE_COUNT; -} - -static void airport_close(dongle_t *self) -{ - IRDA_DEBUG(2, __FUNCTION__ "()\n"); - /* Power off dongle */ - self->set_dtr_rts(self->dev, FALSE, FALSE); - - MOD_DEC_USE_COUNT; -} - -static void airport_set_command_mode(dongle_t *self) -{ - IRDA_DEBUG(2, __FUNCTION__ "()\n"); - self->set_dtr_rts(self->dev, FALSE, TRUE); -} - -static void airport_set_normal_mode(dongle_t *self) -{ - IRDA_DEBUG(2, __FUNCTION__ "()\n"); - self->set_dtr_rts(self->dev, TRUE, TRUE); -} - -void airport_write_char(dongle_t *self, unsigned char c) -{ - int actual; - IRDA_DEBUG(2, __FUNCTION__ "(,0x%x)\n", c & 0xff); - actual = self->write(self->dev, &c, 1); - ASSERT(actual == 1, return;); -} - -#define JIFFIES_TO_MSECS(j) ((j)*1000/HZ) - -static int airport_waitfor_char(dongle_t *self, unsigned char c) -{ - __u8 buf[100]; - int i, found = FALSE; - int before; - int len; - - IRDA_DEBUG(2, __FUNCTION__ "(,0x%x)\n", c); - - /* Sleep approx. 10 ms */ - before = jiffies; - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(MSECS_TO_JIFFIES(20)); - IRDA_DEBUG(4, __FUNCTION__ " waited %ldms\n", - JIFFIES_TO_MSECS(jiffies - before)); - - len = self->read(self->dev, buf, 100); - - for (i = 0; !found && i < len; i++ ) { - /* IRDA_DEBUG(6, __FUNCTION__ " 0x02x\n", idev->rx_buff.data[i]); */ - found = c == buf[i]; - } - - IRDA_DEBUG(2, __FUNCTION__ " returns %s\n", (found ? "true" : "false")); - return found; -} - -static int airport_check_command_mode(dongle_t *self) -{ - int i; - int found = FALSE; - - IRDA_DEBUG(2, __FUNCTION__ "()\n"); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(MSECS_TO_JIFFIES(20)); - airport_set_command_mode(self); - - /* Loop until the time expires (200ms) or we get the magic char. */ - - for ( i = 0 ; i < 25 ; i++ ) { - airport_write_char(self, 0xff); - if (airport_waitfor_char(self, 0xc3)) { - found = TRUE; - break; - } - } - - if (found) { - IRDA_DEBUG(2, __FUNCTION__ " OK. (%d)\n", i); - } else { - IRDA_DEBUG(0, __FUNCTION__ " FAILED!\n"); - } - return found; -} - -static int airport_write_register(dongle_t *self, unsigned char reg) -{ - int ok = FALSE; - int i; - - IRDA_DEBUG(4, __FUNCTION__ "(,0x%x)\n", reg); - airport_check_command_mode(self); - - for ( i = 0 ; i < 6 ; i++ ) { - airport_write_char(self, reg); - if (!airport_waitfor_char(self, reg)) - continue; - - /* Now read it back */ - airport_write_char(self, (reg << 4) | 0x0f); - if (airport_waitfor_char(self, reg)) { - ok = TRUE; - break; - } - } - - airport_set_normal_mode(self); - if (ok) { - IRDA_DEBUG(4, __FUNCTION__ "(,0x%x) returns OK\n", reg); - } else { - IRDA_DEBUG(0, __FUNCTION__ "(,0x%x) returns False!\n", reg); - } - return ok; -} - - -/* - * Function airport_change_speed (self, speed) - * - * Change speed of the Airport type IrDA dongles. - */ -static void airport_change_speed(dongle_t *self, __u32 speed) -{ - __u32 current_baudrate; - int baudcode; - - IRDA_DEBUG(4, __FUNCTION__ "(,%d)\n", speed); - - ASSERT(self != NULL, return;); - - /* Find the correct baudrate code for the required baudrate */ - switch (speed) { - case 2400: baudcode = 0x10; break; - case 4800: baudcode = 0x20; break; - case 9600: baudcode = 0x30; break; - case 19200: baudcode = 0x40; break; - case 38400: baudcode = 0x50; break; - case 57600: baudcode = 0x60; break; - case 115200: baudcode = 0x70; break; - default: - IRDA_DEBUG(0, __FUNCTION__ " bad baud rate: %d\n", speed); - return; - } - - current_baudrate = self->speed; - IRDA_DEBUG(4, __FUNCTION__ " current baudrate: %d\n", current_baudrate); - - self->set_mode(self->dev, IRDA_RAW); - - /* Set the new speed in both registers */ - if (airport_write_register(self, baudcode)) { - if (airport_write_register(self, baudcode|0x01)) { - /* ok */ - } else { - IRDA_DEBUG(0, __FUNCTION__ - " Cannot set new speed in second register\n"); - } - } else { - IRDA_DEBUG(0, __FUNCTION__ - " Cannot set new speed in first register\n"); - } - - self->set_mode(self->dev, IRDA_IRLAP); - - /* How do I signal an error in these functions? */ - - IRDA_DEBUG(4, __FUNCTION__ " returning\n"); -} - -int airport_change_speed_wrapper(struct irda_task *task) -{ - dongle_t *self = (dongle_t *) task->instance; - __u32 speed = (__u32) task->param; - - irda_execute_as_process(self, (TODO_CALLBACK) airport_change_speed, - speed); - - irda_task_next_state(task, IRDA_TASK_DONE); - - return 0; -} - -/* - * Function airport_reset (self) - * - * Reset the Airport type dongle. Warning, this function must only be - * called with a process context! - * - */ -static void airport_reset(dongle_t *self) -{ - int ok; - - IRDA_DEBUG(2, __FUNCTION__ "()\n"); - ASSERT(self != NULL, return;); - - self->set_mode(self->dev, IRDA_RAW); - - airport_set_normal_mode(self); - - /* Sleep 2000 ms */ - IRDA_DEBUG(2, __FUNCTION__ " waiting for powerup\n"); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(MSECS_TO_JIFFIES(2000)); - IRDA_DEBUG(2, __FUNCTION__ " finished waiting for powerup\n"); - - /* set dongle speed to 9600 */ - ok = TRUE; - - if (ok) - ok = airport_write_register(self, 0x30); - if (!ok) - MESSAGE(__FUNCTION__ "() dongle not connected?\n"); - if (ok) - ok = airport_write_register(self, 0x31); - - if (ok) - ok = airport_write_register(self, 0x02); - if (ok) - ok = airport_write_register(self, 0x03); - - if (ok) { - ok = airport_check_command_mode(self); - - if (ok) { - airport_write_char(self, 0x04); - ok = airport_waitfor_char(self, 0x04); - } - airport_set_normal_mode(self); - } - - self->set_mode(self->dev, IRDA_IRLAP); - - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(MSECS_TO_JIFFIES(20)); - IRDA_DEBUG(4, __FUNCTION__ " waited 20ms\n"); - - self->speed = 9600; - if (!ok) - MESSAGE(__FUNCTION__ "() failed.\n"); - IRDA_DEBUG(2, __FUNCTION__ " returning.\n"); -} - -int airport_reset_wrapper(struct irda_task *task) -{ - dongle_t *self = (dongle_t *) task->instance; - - irda_execute_as_process(self, (TODO_CALLBACK) airport_reset, 0); - - irda_task_next_state(task, IRDA_TASK_DONE); - - return 0; -} - -#ifdef MODULE - -MODULE_AUTHOR("Fons Botman <budely@tref.nl>"); -MODULE_DESCRIPTION("Adaptec Airport 1000 and 2000 dongle driver"); - -/* - * Function init_module (void) - * - * Initialize Airport module - * - */ -int init_module(void) -{ - return airport_init(); -} - -/* - * Function cleanup_module (void) - * - * Cleanup Airport module - * - */ -void cleanup_module(void) -{ - airport_cleanup(); -} - -#endif diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c index 352dddecc..d8832292a 100644 --- a/drivers/net/irda/irport.c +++ b/drivers/net/irda/irport.c @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli <dagb@cs.uit.no> * Created at: Sun Aug 3 13:49:59 1997 - * Modified at: Wed Jan 5 13:59:38 2000 + * Modified at: Fri Jan 28 20:22:38 2000 * Modified by: Dag Brattli <dagb@cs.uit.no> * Sources: serial.c by Linus Torvalds * @@ -161,20 +161,19 @@ irport_open(int i, unsigned int iobase, unsigned int irq) self->index = i; /* Initialize IO */ - self->io.iobase = iobase; + self->io.sir_base = iobase; + self->io.sir_ext = IO_EXTENT; self->io.irq = irq; - self->io.io_ext = IO_EXTENT; self->io.fifo_size = 16; /* Lock the port that we need */ - ret = check_region(self->io.iobase, self->io.io_ext); + ret = check_region(self->io.sir_base, self->io.sir_ext); if (ret < 0) { IRDA_DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n", - self->io.iobase); - /* irport_cleanup(self->self); */ + self->io.sir_base); return NULL; } - request_region(self->io.iobase, self->io.io_ext, driver_name); + request_region(self->io.sir_base, self->io.sir_ext, driver_name); /* Initialize QoS for this device */ irda_init_max_qos_capabilies(&self->qos); @@ -218,7 +217,6 @@ irport_open(int i, unsigned int iobase, unsigned int irq) ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); return NULL; } - self->netdev = dev; /* May be overridden by piggyback drivers */ @@ -268,19 +266,19 @@ int irport_close(struct irport_cb *self) /* Release the IO-port that this driver is using */ IRDA_DEBUG(0 , __FUNCTION__ "(), Releasing Region %03x\n", - self->io.iobase); - release_region(self->io.iobase, self->io.io_ext); + self->io.sir_base); + release_region(self->io.sir_base, self->io.sir_ext); if (self->tx_buff.head) kfree(self->tx_buff.head); if (self->rx_buff.head) kfree(self->rx_buff.head); - + /* Remove ourselves */ dev_self[self->index] = NULL; kfree(self); - + return 0; } @@ -289,7 +287,7 @@ void irport_start(struct irport_cb *self) unsigned long flags; int iobase; - iobase = self->io.iobase; + iobase = self->io.sir_base; spin_lock_irqsave(&self->lock, flags); @@ -310,7 +308,7 @@ void irport_stop(struct irport_cb *self) unsigned long flags; int iobase; - iobase = self->io.iobase; + iobase = self->io.sir_base; spin_lock_irqsave(&self->lock, flags); @@ -355,7 +353,7 @@ void irport_change_speed(void *priv, __u32 speed) ASSERT(self != NULL, return;); - iobase = self->io.iobase; + iobase = self->io.sir_base; /* Update accounting for new speed */ self->io.speed = speed; @@ -431,7 +429,7 @@ int __irport_change_speed(struct irda_task *task) break; case IRDA_TASK_CHILD_INIT: /* Go to default speed */ - irport_change_speed(self, 9600); + self->change_speed(self->priv, 9600); /* Change speed of dongle */ if (irda_task_execute(self->dongle, @@ -454,7 +452,7 @@ int __irport_change_speed(struct irda_task *task) break; case IRDA_TASK_CHILD_DONE: /* Finally we are ready to change the speed */ - irport_change_speed(self, speed); + self->change_speed(self->priv, speed); irda_task_next_state(task, IRDA_TASK_DONE); break; @@ -484,7 +482,7 @@ static void irport_write_wakeup(struct irport_cb *self) IRDA_DEBUG(4, __FUNCTION__ "()\n"); - iobase = self->io.iobase; + iobase = self->io.sir_base; /* Finished with frame? */ if (self->tx_buff.len > 0) { @@ -598,7 +596,6 @@ int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev) { struct irport_cb *self; unsigned long flags; - int actual = 0; int iobase; __u32 speed; @@ -607,7 +604,7 @@ int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev) self = (struct irport_cb *) dev->priv; ASSERT(self != NULL, return 0;); - iobase = self->io.iobase; + iobase = self->io.sir_base; /* Lock transmit buffer */ if (irda_lock((void *) &dev->tbusy) == FALSE) { @@ -617,7 +614,7 @@ int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev) WARNING("%s: transmit timed out\n", dev->name); irport_start(self); - irport_change_speed(self, self->io.speed ); + self->change_speed(self->priv, self->io.speed); dev->trans_start = jiffies; } @@ -635,8 +632,7 @@ int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev) self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, self->tx_buff.truesize); - self->tx_buff.data += actual; - self->tx_buff.len -= actual; + self->stats.tx_bytes += self->tx_buff.len; /* Turn on transmit finished interrupt. Will fire immediately! */ outb(UART_IER_THRI, iobase+UART_IER); @@ -661,7 +657,7 @@ static void irport_receive(struct irport_cb *self) ASSERT(self != NULL, return;); - iobase = self->io.iobase; + iobase = self->io.sir_base; /* * Receive all characters in Rx FIFO, unwrap and unstuff them. @@ -702,15 +698,16 @@ void irport_interrupt(int irq, void *dev_id, struct pt_regs *regs) dev->interrupt = 1; - iobase = self->io.iobase; + iobase = self->io.sir_base; iir = inb(iobase+UART_IIR) & UART_IIR_ID; while (iir) { /* Clear interrupt */ lsr = inb(iobase+UART_LSR); - IRDA_DEBUG(4, __FUNCTION__ "(), iir=%02x, lsr=%02x, iobase=%#x\n", - iir, lsr, iobase); + IRDA_DEBUG(4, __FUNCTION__ + "(), iir=%02x, lsr=%02x, iobase=%#x\n", + iir, lsr, iobase); switch (iir) { case UART_IIR_RLSI: @@ -765,7 +762,7 @@ int irport_net_open(struct net_device *dev) ASSERT(dev != NULL, return -1;); self = (struct irport_cb *) dev->priv; - iobase = self->io.iobase; + iobase = self->io.sir_base; if (request_irq(self->io.irq, self->interrupt, 0, dev->name, (void *) dev)) @@ -809,7 +806,7 @@ int irport_net_close(struct net_device *dev) ASSERT(self != NULL, return -1;); - iobase = self->io.iobase; + iobase = self->io.sir_base; /* Stop device */ dev->tbusy = 1; @@ -840,7 +837,7 @@ void irport_wait_until_sent(struct irport_cb *self) { int iobase; - iobase = self->io.iobase; + iobase = self->io.sir_base; /* Wait until Tx FIFO is empty */ while (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) { @@ -875,7 +872,7 @@ static int irport_set_dtr_rts(struct net_device *dev, int dtr, int rts) ASSERT(self != NULL, return -1;); - iobase = self->io.iobase; + iobase = self->io.sir_base; if (dtr) dtr = UART_MCR_DTR; @@ -895,7 +892,7 @@ static int irport_raw_write(struct net_device *dev, __u8 *buf, int len) ASSERT(self != NULL, return -1;); - iobase = self->io.iobase; + iobase = self->io.sir_base; /* Tx FIFO should be empty! */ if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) { diff --git a/drivers/net/irda/irtty.c b/drivers/net/irda/irtty.c index 2ec4eba14..370a9c7fe 100644 --- a/drivers/net/irda/irtty.c +++ b/drivers/net/irda/irtty.c @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli <dagb@cs.uit.no> * Created at: Tue Dec 9 21:18:38 1997 - * Modified at: Wed Jan 5 14:00:13 2000 + * Modified at: Fri Jan 14 21:02:27 2000 * Modified by: Dag Brattli <dagb@cs.uit.no> * Sources: slip.c by Laurence Culhane, <loz@holmes.demon.co.uk> * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> @@ -233,6 +233,8 @@ static int irtty_open(struct tty_struct *tty) ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); return -ENOMEM; } + /* dev_alloc doesn't clear the struct */ + memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct net_device)-sizeof(char*)); dev->priv = (void *) self; self->netdev = dev; @@ -654,6 +656,7 @@ static int irtty_hard_xmit(struct sk_buff *skb, struct net_device *dev) self->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); dev->trans_start = jiffies; + self->stats.tx_bytes += self->tx_buff.len; if (self->tty->driver.write) actual = self->tty->driver.write(self->tty, 0, @@ -663,9 +666,6 @@ static int irtty_hard_xmit(struct sk_buff *skb, struct net_device *dev) self->tx_buff.data += actual; self->tx_buff.len -= actual; - self->stats.tx_packets++; - self->stats.tx_bytes += self->tx_buff.len; - dev_kfree_skb(skb); return 0; @@ -709,6 +709,8 @@ static void irtty_write_wakeup(struct tty_struct *tty) self->tx_buff.data += actual; self->tx_buff.len -= actual; + + self->stats.tx_packets++; } else { /* * Now serial buffer is almost free & we can start diff --git a/drivers/net/irda/nsc_fir.c b/drivers/net/irda/nsc-ircc.c index affd1d8fa..e8aaa8459 100644 --- a/drivers/net/irda/nsc_fir.c +++ b/drivers/net/irda/nsc-ircc.c @@ -1,12 +1,12 @@ /********************************************************************* * - * Filename: nsc_fir.c + * Filename: nsc-ircc.c * Version: 1.0 * Description: Driver for the NSC PC'108 and PC'338 IrDA chipsets * Status: Stable. * Author: Dag Brattli <dagb@cs.uit.no> * Created at: Sat Nov 7 21:43:15 1998 - * Modified at: Wed Jan 5 13:59:21 2000 + * Modified at: Fri Jan 28 12:10:10 2000 * Modified by: Dag Brattli <dagb@cs.uit.no> * * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no> @@ -41,8 +41,9 @@ * ********************************************************************/ -#include <linux/module.h> #include <linux/config.h> +#include <linux/module.h> + #include <linux/kernel.h> #include <linux/types.h> #include <linux/skbuff.h> @@ -67,29 +68,38 @@ #include <net/irda/irlap_frame.h> #include <net/irda/irda_device.h> -#include <net/irda/nsc_fir.h> +#include <net/irda/nsc-ircc.h> #define CHIP_IO_EXTENT 8 #define BROKEN_DONGLE_ID -/* - * Define if you have multiple NSC IrDA controllers in your machine. Not - * enabled by default since some single chips detects at multiple addresses - */ -#undef CONFIG_NSC_FIR_MULTIPLE - -static char *driver_name = "nsc_fir"; +static char *driver_name = "nsc-ircc"; /* Module parameters */ static int qos_mtt_bits = 0x07; /* 1 ms or more */ static int dongle_id = 0; -static unsigned int io[] = { 0x2f8, 0x2f8, 0x2f8, 0x2f8, 0x2f8 }; -static unsigned int io2[] = { 0x150, 0x398, 0xea, 0x15c, 0x2e }; -static unsigned int irq[] = { 3, 3, 3, 3, 3 }; -static unsigned int dma[] = { 0, 0, 0, 0, 3 }; +/* Use BIOS settions by default, but user may supply module parameters */ +static unsigned int io[] = { ~0, ~0, ~0, ~0 }; +static unsigned int irq[] = { 0, 0, 0, 0, 0 }; +static unsigned int dma[] = { 0, 0, 0, 0, 0 }; + +static int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info); +static int nsc_ircc_probe_338(nsc_chip_t *chip, chipio_t *info); +static int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info); +static int nsc_ircc_init_338(nsc_chip_t *chip, chipio_t *info); + +/* These are the known NSC chips */ +static nsc_chip_t chips[] = { + { "PC87108", { 0x150, 0x398, 0xea }, 0x05, 0x10, 0xf0, + nsc_ircc_probe_108, nsc_ircc_init_108 }, + { "PC87338", { 0x398, 0x15c, 0x2e }, 0x08, 0xb0, 0xf0, + nsc_ircc_probe_338, nsc_ircc_init_338 }, + { NULL } +}; -static struct nsc_fir_cb *dev_self[] = { NULL, NULL, NULL, NULL, NULL }; +/* Max 4 instances for now */ +static struct nsc_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL }; static char *dongle_types[] = { "Differential serial interface", @@ -111,143 +121,182 @@ static char *dongle_types[] = { }; /* Some prototypes */ -static int nsc_fir_open(int i, unsigned int iobase, unsigned int board_addr, - unsigned int irq, unsigned int dma); +static int nsc_ircc_open(int i, chipio_t *info); #ifdef MODULE -static int nsc_fir_close(struct nsc_fir_cb *self); +static int nsc_ircc_close(struct nsc_ircc_cb *self); #endif /* MODULE */ -static int nsc_fir_probe(int iobase, int board_addr, int irq, int dma); -static void nsc_fir_pio_receive(struct nsc_fir_cb *self); -static int nsc_fir_dma_receive(struct nsc_fir_cb *self); -static int nsc_fir_dma_receive_complete(struct nsc_fir_cb *self, int iobase); -static int nsc_fir_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev); -static int nsc_fir_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev); -static int nsc_fir_pio_write(int iobase, __u8 *buf, int len, int fifo_size); -static void nsc_fir_dma_xmit(struct nsc_fir_cb *self, int iobase); -static void nsc_fir_change_speed(struct nsc_fir_cb *self, __u32 baud); -static void nsc_fir_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static int nsc_fir_is_receiving(struct nsc_fir_cb *self); -static int nsc_fir_read_dongle_id (int iobase); -static void nsc_fir_init_dongle_interface (int iobase, int dongle_id); - -static int nsc_fir_net_init(struct net_device *dev); -static int nsc_fir_net_open(struct net_device *dev); -static int nsc_fir_net_close(struct net_device *dev); -static int nsc_fir_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static struct net_device_stats *nsc_fir_net_get_stats(struct net_device *dev); +static int nsc_ircc_setup(chipio_t *info); +static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self); +static int nsc_ircc_dma_receive(struct nsc_ircc_cb *self); +static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase); +static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev); +static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev); +static int nsc_ircc_pio_write(int iobase, __u8 *buf, int len, int fifo_size); +static void nsc_ircc_dma_xmit(struct nsc_ircc_cb *self, int iobase); +static void nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 baud); +static void nsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static int nsc_ircc_is_receiving(struct nsc_ircc_cb *self); +static int nsc_ircc_read_dongle_id (int iobase); +static void nsc_ircc_init_dongle_interface (int iobase, int dongle_id); + +static int nsc_ircc_net_init(struct net_device *dev); +static int nsc_ircc_net_open(struct net_device *dev); +static int nsc_ircc_net_close(struct net_device *dev); +static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev); #ifdef CONFIG_APM -static int nsc_fir_apmproc(apm_event_t event); +static int nsc_ircc_apmproc(apm_event_t event); #endif /* CONFIG_APM */ + /* - * Function nsc_fir_init () + * Function nsc_ircc_init () * * Initialize chip. Just try to find out how many chips we are dealing with * and where they are */ -int __init nsc_fir_init(void) +int __init nsc_ircc_init(void) { + chipio_t info; + nsc_chip_t *chip; int ret = -ENODEV; - int ioaddr; - int i; + int cfg_base; + int cfg, id; + int reg; + int i = 0; + + /* Probe for all the NSC chipsets we know about */ + for (chip=chips; chip->name ; chip++,i++) { + IRDA_DEBUG(2, __FUNCTION__"(), Probing for %s ...\n", + chip->name); + + /* Try all config registers for this chip */ + for (cfg=0; cfg<3; cfg++) { + cfg_base = chip->cfg[cfg]; + if (!cfg_base) + continue; + + memset(&info, 0, sizeof(chipio_t)); + info.cfg_base = cfg_base; + info.fir_base = io[i]; + info.dma = dma[i]; + info.irq = irq[i]; + + /* Read index register */ + reg = inb(cfg_base); + if (reg == 0xff) { + IRDA_DEBUG(2, __FUNCTION__ + "() no chip at 0x%03x\n", cfg_base); + continue; + } + + /* Read chip identification register */ + outb(chip->cid_index, cfg_base); + id = inb(cfg_base+1); + if ((id & chip->cid_mask) == chip->cid_value) { + IRDA_DEBUG(2, __FUNCTION__ + "() Found %s chip, revision=%d\n", + chip->name, id & ~chip->cid_mask); + /* + * If the user supplies the base address, then + * we init the chip, if not we probe the values + * set by the BIOS + */ + if (io[i] < 2000) { + chip->init(chip, &info); + } else + chip->probe(chip, &info); + if (nsc_ircc_open(i, &info) == 0) + ret = 0; + i++; + } else { + IRDA_DEBUG(2, __FUNCTION__ + "(), Wrong chip id=0x%02x\n", id); + } + } + + } #ifdef CONFIG_APM - apm_register_callback(nsc_fir_apmproc); + /* Make sure at least one chip was found before enabling APM */ + if (ret == 0) + apm_register_callback(nsc_ircc_apmproc); #endif /* CONFIG_APM */ - for (i=0; (io[i] < 2000) && (i < 5); i++) { - ioaddr = io[i]; - if (check_region(ioaddr, CHIP_IO_EXTENT) < 0) - continue; - if (nsc_fir_open(i, io[i], io2[i], irq[i], dma[i]) == 0) - { -#ifdef CONFIG_NSC_FIR_MULTIPLE - ret = 0; -#else - return 0; -#endif - } - } - return ret; } /* - * Function nsc_fir_cleanup () + * Function nsc_ircc_cleanup () * * Close all configured chips * */ #ifdef MODULE -static void nsc_fir_cleanup(void) +static void nsc_ircc_cleanup(void) { int i; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - #ifdef CONFIG_APM - apm_unregister_callback(nsc_fir_apmproc); + apm_unregister_callback(nsc_ircc_apmproc); #endif /* CONFIG_APM */ - - for (i=0; i < 5; i++) { + for (i=0; i < 4; i++) { if (dev_self[i]) - nsc_fir_close(dev_self[i]); + nsc_ircc_close(dev_self[i]); } } #endif /* MODULE */ /* - * Function nsc_fir_open (iobase, irq) + * Function nsc_ircc_open (iobase, irq) * * Open driver instance * */ -static int -nsc_fir_open(int i, unsigned int iobase, unsigned int board_addr, - unsigned int irq, unsigned int dma) +static int nsc_ircc_open(int i, chipio_t *info) { struct net_device *dev; - struct nsc_fir_cb *self; - int dongle_id; + struct nsc_ircc_cb *self; int ret; int err; IRDA_DEBUG(2, __FUNCTION__ "()\n"); - if ((dongle_id = nsc_fir_probe(iobase, board_addr, irq, dma)) == -1) + if ((nsc_ircc_setup(info)) == -1) return -1; - /* - * Allocate new instance of the driver - */ - self = kmalloc(sizeof(struct nsc_fir_cb), GFP_KERNEL); + /* Allocate new instance of the driver */ + self = kmalloc(sizeof(struct nsc_ircc_cb), GFP_KERNEL); if (self == NULL) { ERROR(__FUNCTION__ "(), can't allocate memory for " "control block!\n"); return -ENOMEM; } - memset(self, 0, sizeof(struct nsc_fir_cb)); + memset(self, 0, sizeof(struct nsc_ircc_cb)); spin_lock_init(&self->lock); /* Need to store self somewhere */ dev_self[i] = self; + self->index = i; /* Initialize IO */ - self->io.iobase = iobase; - self->io.irq = irq; - self->io.io_ext = CHIP_IO_EXTENT; - self->io.dma = dma; + self->io.cfg_base = info->cfg_base; + self->io.fir_base = info->fir_base; + self->io.irq = info->irq; + self->io.fir_ext = CHIP_IO_EXTENT; + self->io.dma = info->dma; self->io.fifo_size = 32; - - /* Lock the port that we need */ - ret = check_region(self->io.iobase, self->io.io_ext); + + /* Reserve the ioports that we need */ + ret = check_region(self->io.fir_base, self->io.fir_ext); if (ret < 0) { - IRDA_DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n", - self->io.iobase); - /* nsc_fir_cleanup(self->self); */ + WARNING(__FUNCTION__ "(), can't get iobase of 0x%03x\n", + self->io.fir_base); + dev_self[i] = NULL; + kfree(self); return -ENODEV; } - request_region(self->io.iobase, self->io.io_ext, driver_name); + request_region(self->io.fir_base, self->io.fir_ext, driver_name); /* Initialize QoS for this device */ irda_init_max_qos_capabilies(&self->qos); @@ -268,13 +317,16 @@ nsc_fir_open(int i, unsigned int iobase, unsigned int board_addr, /* Allocate memory if needed */ self->rx_buff.head = (__u8 *) kmalloc(self->rx_buff.truesize, GFP_KERNEL|GFP_DMA); - if (self->rx_buff.head == NULL) + if (self->rx_buff.head == NULL) { + kfree(self); return -ENOMEM; + } memset(self->rx_buff.head, 0, self->rx_buff.truesize); self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, GFP_KERNEL|GFP_DMA); if (self->tx_buff.head == NULL) { + kfree(self); kfree(self->rx_buff.head); return -ENOMEM; } @@ -298,12 +350,12 @@ nsc_fir_open(int i, unsigned int iobase, unsigned int board_addr, self->netdev = dev; /* Override the network functions we need to use */ - dev->init = nsc_fir_net_init; - dev->hard_start_xmit = nsc_fir_hard_xmit_sir; - dev->open = nsc_fir_net_open; - dev->stop = nsc_fir_net_close; - dev->do_ioctl = nsc_fir_net_ioctl; - dev->get_stats = nsc_fir_net_get_stats; + dev->init = nsc_ircc_net_init; + dev->hard_start_xmit = nsc_ircc_hard_xmit_sir; + dev->open = nsc_ircc_net_open; + dev->stop = nsc_ircc_net_close; + dev->do_ioctl = nsc_ircc_net_ioctl; + dev->get_stats = nsc_ircc_net_get_stats; rtnl_lock(); err = register_netdevice(dev); @@ -312,23 +364,33 @@ nsc_fir_open(int i, unsigned int iobase, unsigned int board_addr, ERROR(__FUNCTION__ "(), register_netdev() failed!\n"); return -1; } - MESSAGE("IrDA: Registered device %s\n", dev->name); + + /* Check if user has supplied the dongle id or not */ + if (!dongle_id) { + dongle_id = nsc_ircc_read_dongle_id(self->io.fir_base); + + MESSAGE("%s, Found dongle: %s\n", driver_name, + dongle_types[dongle_id]); + } else { + MESSAGE("%s, Using dongle: %s\n", driver_name, + dongle_types[dongle_id]); + } self->io.dongle_id = dongle_id; - nsc_fir_init_dongle_interface(iobase, dongle_id); + nsc_ircc_init_dongle_interface(self->io.fir_base, dongle_id); return 0; } #ifdef MODULE /* - * Function nsc_fir_close (self) + * Function nsc_ircc_close (self) * * Close driver instance * */ -static int nsc_fir_close(struct nsc_fir_cb *self) +static int nsc_ircc_close(struct nsc_ircc_cb *self) { int iobase; @@ -336,7 +398,7 @@ static int nsc_fir_close(struct nsc_fir_cb *self) ASSERT(self != NULL, return -1;); - iobase = self->io.iobase; + iobase = self->io.fir_base; /* Remove netdevice */ if (self->netdev) { @@ -347,8 +409,8 @@ static int nsc_fir_close(struct nsc_fir_cb *self) /* Release the PORT that this driver is using */ IRDA_DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", - self->io.iobase); - release_region(self->io.iobase, self->io.io_ext); + self->io.fir_base); + release_region(self->io.fir_base, self->io.fir_ext); if (self->tx_buff.head) kfree(self->tx_buff.head); @@ -356,37 +418,39 @@ static int nsc_fir_close(struct nsc_fir_cb *self) if (self->rx_buff.head) kfree(self->rx_buff.head); + dev_self[self->index] = NULL; kfree(self); - + return 0; } #endif /* MODULE */ /* - * Function nsc_fir_init_807 (iobase, board_addr, irq, dma) + * Function nsc_ircc_init_108 (iobase, cfg_base, irq, dma) * * Initialize the NSC '108 chip * */ -static void nsc_fir_init_807(int iobase, int board_addr, int irq, int dma) +static int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info) { + int cfg_base = info->cfg_base; __u8 temp=0; - outb(2, board_addr); /* Mode Control Register (MCTL) */ - outb(0x00, board_addr+1); /* Disable device */ + outb(2, cfg_base); /* Mode Control Register (MCTL) */ + outb(0x00, cfg_base+1); /* Disable device */ /* Base Address and Interrupt Control Register (BAIC) */ - outb(0, board_addr); - switch (iobase) { - case 0x3e8: outb(0x14, board_addr+1); break; - case 0x2e8: outb(0x15, board_addr+1); break; - case 0x3f8: outb(0x16, board_addr+1); break; - case 0x2f8: outb(0x17, board_addr+1); break; + outb(0, cfg_base); + switch (info->fir_base) { + case 0x3e8: outb(0x14, cfg_base+1); break; + case 0x2e8: outb(0x15, cfg_base+1); break; + case 0x3f8: outb(0x16, cfg_base+1); break; + case 0x2f8: outb(0x17, cfg_base+1); break; default: ERROR(__FUNCTION__ "(), invalid base_address"); } /* Control Signal Routing Register (CSRT) */ - switch (irq) { + switch (info->irq) { case 3: temp = 0x01; break; case 4: temp = 0x02; break; case 5: temp = 0x03; break; @@ -396,90 +460,242 @@ static void nsc_fir_init_807(int iobase, int board_addr, int irq, int dma) case 15: temp = 0x07; break; default: ERROR(__FUNCTION__ "(), invalid irq"); } - outb(1, board_addr); + outb(1, cfg_base); - switch (dma) { - case 0: outb(0x08+temp, board_addr+1); break; - case 1: outb(0x10+temp, board_addr+1); break; - case 3: outb(0x18+temp, board_addr+1); break; + switch (info->dma) { + case 0: outb(0x08+temp, cfg_base+1); break; + case 1: outb(0x10+temp, cfg_base+1); break; + case 3: outb(0x18+temp, cfg_base+1); break; default: ERROR(__FUNCTION__ "(), invalid dma"); } - outb(2, board_addr); /* Mode Control Register (MCTL) */ - outb(0x03, board_addr+1); /* Enable device */ + outb(2, cfg_base); /* Mode Control Register (MCTL) */ + outb(0x03, cfg_base+1); /* Enable device */ + + return 0; +} + +/* + * Function nsc_ircc_probe_108 (chip, info) + * + * + * + */ +static int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info) +{ + int cfg_base = info->cfg_base; + int reg; + + /* Read address and interrupt control register (BAIC) */ + outb(CFG_BAIC, cfg_base); + reg = inb(cfg_base+1); + + switch (reg & 0x03) { + case 0: + info->fir_base = 0x3e8; + break; + case 1: + info->fir_base = 0x2e8; + break; + case 2: + info->fir_base = 0x3f8; + break; + case 3: + info->fir_base = 0x2f8; + break; + } + info->sir_base = info->fir_base; + IRDA_DEBUG(2, __FUNCTION__ "(), probing fir_base=0x%03x\n", + info->fir_base); + + /* Read control signals routing register (CSRT) */ + outb(CFG_CSRT, cfg_base); + reg = inb(cfg_base+1); + + switch (reg & 0x07) { + case 0: + info->irq = -1; + break; + case 1: + info->irq = 3; + break; + case 2: + info->irq = 4; + break; + case 3: + info->irq = 5; + break; + case 4: + info->irq = 7; + break; + case 5: + info->irq = 9; + break; + case 6: + info->irq = 11; + break; + case 7: + info->irq = 15; + break; + } + IRDA_DEBUG(2, __FUNCTION__ "(), probing irq=%d\n", info->irq); + + /* Currently we only read Rx DMA but it will also be used for Tx */ + switch ((reg >> 3) & 0x03) { + case 0: + info->dma = -1; + break; + case 1: + info->dma = 0; + break; + case 2: + info->dma = 1; + break; + case 3: + info->dma = 3; + break; + } + IRDA_DEBUG(2, __FUNCTION__ "(), probing dma=%d\n", info->dma); + + /* Read mode control register (MCTL) */ + outb(CFG_MCTL, cfg_base); + reg = inb(cfg_base+1); + + info->enabled = reg & 0x01; + info->suspended = !((reg >> 1) & 0x01); + + return 0; } /* - * Function nsc_fir_init_338 (iobase, board_addr, irq, dma) + * Function nsc_ircc_init_338 (chip, info) * * Initialize the NSC '338 chip. Remember that the 87338 needs two * consecutive writes to the data registers while CPU interrupts are * disabled. The 97338 does not require this, but shouldn't be any * harm if we do it anyway. */ -static void nsc_fir_init_338(int iobase, int board_addr, int irq, int dma) +static int nsc_ircc_init_338(nsc_chip_t *chip, chipio_t *info) { /* No init yet */ + + return 0; } -static int nsc_fir_find_chip(int board_addr) +/* + * Function nsc_ircc_probe_338 (chip, info) + * + * + * + */ +static int nsc_ircc_probe_338(nsc_chip_t *chip, chipio_t *info) { - __u8 index, id; + int cfg_base = info->cfg_base; + int reg, com = 0; + int pnp; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + /* Read funtion enable register (FER) */ + outb(CFG_FER, cfg_base); + reg = inb(cfg_base+1); - /* Read index register */ - index = inb(board_addr); - if (index == 0xff) { - IRDA_DEBUG(0, __FUNCTION__ "(), no chip at 0x%03x\n", - board_addr); - return -1; - } + info->enabled = (reg >> 2) & 0x01; + + /* Check if we are in Legacy or PnP mode */ + outb(CFG_PNP0, cfg_base); + reg = inb(cfg_base+1); + + pnp = (reg >> 4) & 0x01; + if (pnp) { + IRDA_DEBUG(2, "(), Chip is in PnP mode\n"); + outb(0x46, cfg_base); + reg = (inb(cfg_base+1) & 0xfe) << 2; + + outb(0x47, cfg_base); + reg |= ((inb(cfg_base+1) & 0xfc) << 8); - /* Read chip identification register (SID) for the PC97338 */ - outb(8, board_addr); - id = inb(board_addr+1); - if ((id & 0xf0) == PC97338) { - MESSAGE("%s, Found NSC PC97338 chip, revision=%d\n", - driver_name, id & 0x0f); - return PC97338; - } - - /* Read device identification (DID) for the PC87108 */ - outb(5, board_addr); - id = inb(board_addr+1); - if ((id & 0xf0) == PC87108) { - MESSAGE("%s, Found NSC PC87108 chip, revision=%d\n", - driver_name, id & 0x0f); - return PC87108; + info->fir_base = reg; + } else { + /* Read function address register (FAR) */ + outb(CFG_FAR, cfg_base); + reg = inb(cfg_base+1); + + switch ((reg >> 4) & 0x03) { + case 0: + info->fir_base = 0x3f8; + break; + case 1: + info->fir_base = 0x2f8; + break; + case 2: + com = 3; + break; + case 3: + com = 4; + break; + } + + if (com) { + switch ((reg >> 6) & 0x03) { + case 0: + if (com == 3) + info->fir_base = 0x3e8; + else + info->fir_base = 0x2e8; + break; + case 1: + if (com == 3) + info->fir_base = 0x338; + else + info->fir_base = 0x238; + break; + case 2: + if (com == 3) + info->fir_base = 0x2e8; + else + info->fir_base = 0x2e0; + break; + case 3: + if (com == 3) + info->fir_base = 0x220; + else + info->fir_base = 0x228; + break; + } + } } + info->sir_base = info->fir_base; + + /* Read PnP register 1 (PNP1) */ + outb(CFG_PNP1, cfg_base); + reg = inb(cfg_base+1); + + info->irq = reg >> 4; + + /* Read PnP register 3 (PNP3) */ + outb(CFG_PNP3, cfg_base); + reg = inb(cfg_base+1); + + info->dma = (reg & 0x07) - 1; - return -1; + /* Read power and test register (PTR) */ + outb(CFG_PTR, cfg_base); + reg = inb(cfg_base+1); + + info->suspended = reg & 0x01; + + return 0; } /* - * Function nsc_fir_probe (iobase, board_addr, irq, dma) + * Function nsc_ircc_setup (info) * * Returns non-negative on success. * */ -static int nsc_fir_probe(int iobase, int board_addr, int irq, int dma) +static int nsc_ircc_setup(chipio_t *info) { int version; - __u8 chip; - - chip = nsc_fir_find_chip(board_addr); - switch (chip) { - case PC87108: - nsc_fir_init_807(iobase, board_addr, irq, dma); - break; - case PC97338: - nsc_fir_init_338(iobase, board_addr, irq, dma); - break; - default: - /* Found no chip */ - return -1; - } + int iobase = info->fir_base; /* Read the Module ID */ switch_bank(iobase, BANK3); @@ -490,23 +706,13 @@ static int nsc_fir_probe(int iobase, int board_addr, int irq, int dma) ERROR("%s, Wrong chip version %02x\n", driver_name, version); return -1; } - MESSAGE("%s, Found chip at base=0x%04x\n", driver_name, board_addr); + MESSAGE("%s, Found chip at base=0x%03x\n", driver_name, + info->cfg_base); /* Switch to advanced mode */ switch_bank(iobase, BANK2); outb(ECR1_EXT_SL, iobase+ECR1); switch_bank(iobase, BANK0); - - /* Check if user has supplied the dongle id or not */ - if (!dongle_id) { - dongle_id = nsc_fir_read_dongle_id(iobase); - - MESSAGE("%s, Found dongle: %s\n", driver_name, - dongle_types[dongle_id]); - } else { - MESSAGE("%s, Using dongle: %s\n", driver_name, - dongle_types[dongle_id]); - } /* Set FIFO threshold to TX17, RX16, reset and enable FIFO's */ switch_bank(iobase, BANK0); @@ -533,24 +739,21 @@ static int nsc_fir_probe(int iobase, int board_addr, int irq, int dma) switch_bank(iobase, BANK0); outb(IER_RXHDL_IE, iobase+IER); - return dongle_id; + return 0; } /* - * Function nsc_fir_read_dongle_id (void) + * Function nsc_ircc_read_dongle_id (void) * * Try to read dongle indentification. This procedure needs to be executed * once after power-on/reset. It also needs to be used whenever you suspect * that the user may have plugged/unplugged the IrDA Dongle. - * */ -static int nsc_fir_read_dongle_id (int iobase) +static int nsc_ircc_read_dongle_id (int iobase) { int dongle_id; __u8 bank; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - bank = inb(iobase+BSR); /* Select Bank 7 */ @@ -568,8 +771,7 @@ static int nsc_fir_read_dongle_id (int iobase) #ifdef BROKEN_DONGLE_ID if (dongle_id == 0x0a) dongle_id = 0x09; -#endif - +#endif /* Go back to bank 0 before returning */ switch_bank(iobase, BANK0); @@ -579,14 +781,14 @@ static int nsc_fir_read_dongle_id (int iobase) } /* - * Function nsc_fir_init_dongle_interface (iobase, dongle_id) + * Function nsc_ircc_init_dongle_interface (iobase, dongle_id) * * This function initializes the dongle for the transceiver that is * used. This procedure needs to be executed once after * power-on/reset. It also needs to be used whenever you suspect that * the dongle is changed. */ -static void nsc_fir_init_dongle_interface (int iobase, int dongle_id) +static void nsc_ircc_init_dongle_interface (int iobase, int dongle_id) { int bank; @@ -625,11 +827,11 @@ static void nsc_fir_init_dongle_interface (int iobase, int dongle_id) dongle_types[dongle_id]); break; case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, __FUNCTION__ "(), %s\n", + dongle_types[dongle_id]); break; case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */ - outb_p(0x28, iobase+7); /* Set irsl[0-2] as output */ + outb(0x28, iobase+7); /* Set irsl[0-2] as output */ break; case 0x0A: /* same as */ case 0x0B: /* Reserved */ @@ -668,18 +870,16 @@ static void nsc_fir_init_dongle_interface (int iobase, int dongle_id) } /* set_up_dongle_interface */ /* - * Function nsc_fir_change_dongle_speed (iobase, speed, dongle_id) + * Function nsc_ircc_change_dongle_speed (iobase, speed, dongle_id) * * Change speed of the attach dongle * */ -static void nsc_fir_change_dongle_speed(int iobase, int speed, int dongle_id) +static void nsc_ircc_change_dongle_speed(int iobase, int speed, int dongle_id) { unsigned long flags; __u8 bank; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - /* Save current bank */ bank = inb(iobase+BSR); @@ -714,11 +914,14 @@ static void nsc_fir_change_dongle_speed(int iobase, int speed, int dongle_id) dongle_types[dongle_id]); break; case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n", + IRDA_DEBUG(0, __FUNCTION__ "(), %s\n", dongle_types[dongle_id]); + outb(0x00, iobase+4); + if (speed > 115200) + outb(0x01, iobase+4); + break; case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */ - switch_bank(iobase, BANK7); - outb_p(0x01, iobase+4); + outb(0x01, iobase+4); if (speed == 4000000) { save_flags(flags); @@ -727,7 +930,7 @@ static void nsc_fir_change_dongle_speed(int iobase, int speed, int dongle_id) outb(0x80, iobase+4); restore_flags(flags); } else - outb_p(0x00, iobase+4); + outb(0x00, iobase+4); break; case 0x0A: /* same as */ case 0x0B: /* Reserved */ @@ -754,12 +957,12 @@ static void nsc_fir_change_dongle_speed(int iobase, int speed, int dongle_id) } /* - * Function nsc_fir_change_speed (self, baud) + * Function nsc_ircc_change_speed (self, baud) * * Change the speed of the device * */ -static void nsc_fir_change_speed(struct nsc_fir_cb *self, __u32 speed) +static void nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 speed) { struct net_device *dev = self->netdev; __u8 mcr = MCR_SIR; @@ -770,7 +973,7 @@ static void nsc_fir_change_speed(struct nsc_fir_cb *self, __u32 speed) ASSERT(self != NULL, return;); - iobase = self->io.iobase; + iobase = self->io.fir_base; /* Update accounting for new speed */ self->io.speed = speed; @@ -821,7 +1024,7 @@ static void nsc_fir_change_speed(struct nsc_fir_cb *self, __u32 speed) outb(mcr | MCR_TX_DFR, iobase+MCR); /* Give some hits to the transceiver */ - nsc_fir_change_dongle_speed(iobase, speed, self->io.dongle_id); + nsc_ircc_change_dongle_speed(iobase, speed, self->io.dongle_id); /* Set FIFO threshold to TX17, RX16 */ switch_bank(iobase, BANK0); @@ -844,12 +1047,12 @@ static void nsc_fir_change_speed(struct nsc_fir_cb *self, __u32 speed) switch_bank(iobase, BANK0); if (speed > 115200) { /* Install FIR xmit handler */ - dev->hard_start_xmit = nsc_fir_hard_xmit_fir; + dev->hard_start_xmit = nsc_ircc_hard_xmit_fir; outb(IER_SFIF_IE, iobase+IER); - nsc_fir_dma_receive(self); + nsc_ircc_dma_receive(self); } else { /* Install SIR xmit handler */ - dev->hard_start_xmit = nsc_fir_hard_xmit_sir; + dev->hard_start_xmit = nsc_ircc_hard_xmit_sir; outb(IER_RXHDL_IE, iobase+IER); } @@ -858,24 +1061,24 @@ static void nsc_fir_change_speed(struct nsc_fir_cb *self, __u32 speed) } /* - * Function nsc_fir_hard_xmit (skb, dev) + * Function nsc_ircc_hard_xmit (skb, dev) * * Transmit the frame! * */ -static int nsc_fir_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) +static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) { - struct nsc_fir_cb *self; + struct nsc_ircc_cb *self; unsigned long flags; int iobase; __u32 speed; __u8 bank; - self = (struct nsc_fir_cb *) dev->priv; + self = (struct nsc_ircc_cb *) dev->priv; ASSERT(self != NULL, return 0;); - iobase = self->io.iobase; + iobase = self->io.fir_base; /* Lock transmit buffer */ if (irda_lock((void *) &dev->tbusy) == FALSE) @@ -894,6 +1097,8 @@ static int nsc_fir_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, self->tx_buff.truesize); + + self->stats.tx_bytes += self->tx_buff.len; /* Add interrupt on tx low level (will fire immediately) */ switch_bank(iobase, BANK0); @@ -909,20 +1114,17 @@ static int nsc_fir_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) return 0; } -static int nsc_fir_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) +static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) { - struct nsc_fir_cb *self; + struct nsc_ircc_cb *self; unsigned long flags; int iobase; __u32 speed; __u8 bank; int mtt, diff; - self = (struct nsc_fir_cb *) dev->priv; - - ASSERT(self != NULL, return 0;); - - iobase = self->io.iobase; + self = (struct nsc_ircc_cb *) dev->priv; + iobase = self->io.fir_base; /* Lock transmit buffer */ if (irda_lock((void *) &dev->tbusy) == FALSE) @@ -942,6 +1144,8 @@ static int nsc_fir_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) self->tx_fifo.queue[self->tx_fifo.free].len = skb->len; self->tx_fifo.tail += skb->len; + self->stats.tx_bytes += skb->len; + memcpy(self->tx_fifo.queue[self->tx_fifo.free].start, skb->data, skb->len); @@ -950,10 +1154,11 @@ static int nsc_fir_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) /* Start transmit only if there is currently no transmit going on */ if (self->tx_fifo.len == 1) { + /* Check if we must wait the min turn time or not */ mtt = irda_get_mtt(skb); if (mtt) { /* Check how much time we have used already */ - do_gettimeofday(&self->now); + get_fast_time(&self->now); diff = self->now.tv_usec - self->stamp.tv_usec; if (diff < 0) diff += 1000000; @@ -963,9 +1168,15 @@ static int nsc_fir_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) */ if (mtt > diff) { mtt -= diff; + + /* + * Use timer if delay larger than 125 us, and + * use udelay for smaller values which should + * be acceptable + */ if (mtt > 125) { /* Adjust for timer resolution */ - mtt = mtt / 125 + 1; + mtt = mtt / 125; /* Setup timer */ switch_bank(iobase, BANK4); @@ -985,34 +1196,35 @@ static int nsc_fir_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) } else udelay(mtt); } - } - + } /* Enable DMA interrupt */ switch_bank(iobase, BANK0); outb(IER_DMA_IE, iobase+IER); - nsc_fir_dma_xmit(self, iobase); + + /* Transmit frame */ + nsc_ircc_dma_xmit(self, iobase); } + out: /* Not busy transmitting anymore if window is not full */ - if (self->tx_fifo.len < MAX_WINDOW) + if (self->tx_fifo.free < MAX_TX_WINDOW) dev->tbusy = 0; - out: + /* Restore bank register */ outb(bank, iobase+BSR); spin_unlock_irqrestore(&self->lock, flags); - dev_kfree_skb(skb); return 0; } /* - * Function nsc_fir_dma_xmit (self, iobase) + * Function nsc_ircc_dma_xmit (self, iobase) * * Transmit data using DMA * */ -static void nsc_fir_dma_xmit(struct nsc_fir_cb *self, int iobase) +static void nsc_ircc_dma_xmit(struct nsc_ircc_cb *self, int iobase) { int bsr; @@ -1043,13 +1255,13 @@ static void nsc_fir_dma_xmit(struct nsc_fir_cb *self, int iobase) } /* - * Function nsc_fir_pio_xmit (self, iobase) + * Function nsc_ircc_pio_xmit (self, iobase) * * Transmit data using PIO. Returns the number of bytes that actually * got transfered * */ -static int nsc_fir_pio_write(int iobase, __u8 *buf, int len, int fifo_size) +static int nsc_ircc_pio_write(int iobase, __u8 *buf, int len, int fifo_size) { int actual = 0; __u8 bank; @@ -1064,6 +1276,7 @@ static int nsc_fir_pio_write(int iobase, __u8 *buf, int len, int fifo_size) IRDA_DEBUG(4, __FUNCTION__ "(), warning, FIFO not empty yet!\n"); + /* FIFO may still be filled to the Tx interrupt threshold */ fifo_size -= 17; } @@ -1083,13 +1296,13 @@ static int nsc_fir_pio_write(int iobase, __u8 *buf, int len, int fifo_size) } /* - * Function nsc_fir_dma_xmit_complete (self) + * Function nsc_ircc_dma_xmit_complete (self) * * The transfer of a frame in finished. This function will only be called * by the interrupt handler * */ -static int nsc_fir_dma_xmit_complete(struct nsc_fir_cb *self) +static int nsc_ircc_dma_xmit_complete(struct nsc_ircc_cb *self) { int iobase; __u8 bank; @@ -1097,7 +1310,7 @@ static int nsc_fir_dma_xmit_complete(struct nsc_fir_cb *self) IRDA_DEBUG(2, __FUNCTION__ "()\n"); - iobase = self->io.iobase; + iobase = self->io.fir_base; /* Save current bank */ bank = inb(iobase+BSR); @@ -1115,11 +1328,11 @@ static int nsc_fir_dma_xmit_complete(struct nsc_fir_cb *self) outb(ASCR_TXUR, iobase+ASCR); } else { self->stats.tx_packets++; - self->stats.tx_bytes += self->tx_buff.len; } - + + /* Check if we need to change the speed */ if (self->new_speed) { - nsc_fir_change_speed(self, self->new_speed); + nsc_ircc_change_speed(self, self->new_speed); self->new_speed = 0; } @@ -1129,17 +1342,24 @@ static int nsc_fir_dma_xmit_complete(struct nsc_fir_cb *self) /* Any frames to be sent back-to-back? */ if (self->tx_fifo.len) { - nsc_fir_dma_xmit(self, iobase); + nsc_ircc_dma_xmit(self, iobase); /* Not finished yet! */ ret = FALSE; + } else { + /* Reset Tx FIFO info */ + self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; + self->tx_fifo.tail = self->tx_buff.head; } - /* Not busy transmitting anymore */ - self->netdev->tbusy = 0; + /* Make sure we have room for more frames */ + if (self->tx_fifo.free < MAX_TX_WINDOW) { + /* Not busy transmitting anymore */ + self->netdev->tbusy = 0; - /* Tell the network layer, that we can accept more frames */ - mark_bh(NET_BH); + /* Tell the network layer, that we can accept more frames */ + mark_bh(NET_BH); + } /* Restore bank */ outb(bank, iobase+BSR); @@ -1148,20 +1368,18 @@ static int nsc_fir_dma_xmit_complete(struct nsc_fir_cb *self) } /* - * Function nsc_fir_dma_receive (self) + * Function nsc_ircc_dma_receive (self) * * Get ready for receiving a frame. The device will initiate a DMA * if it starts to receive a frame. * */ -static int nsc_fir_dma_receive(struct nsc_fir_cb *self) +static int nsc_ircc_dma_receive(struct nsc_ircc_cb *self) { int iobase; __u8 bsr; - ASSERT(self != NULL, return -1;); - - iobase = self->io.iobase; + iobase = self->io.fir_base; /* Reset Tx FIFO info */ self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; @@ -1184,7 +1402,9 @@ static int nsc_fir_dma_receive(struct nsc_fir_cb *self) /* Reset Rx FIFO. This will also flush the ST_FIFO */ switch_bank(iobase, BANK0); outb(FCR_RXSR|FCR_FIFO_EN, iobase+FCR); - self->st_fifo.len = self->st_fifo.tail = self->st_fifo.head = 0; + + self->st_fifo.len = self->st_fifo.pending_bytes = 0; + self->st_fifo.tail = self->st_fifo.head = 0; setup_dma(self->io.dma, self->rx_buff.data, self->rx_buff.truesize, DMA_RX_MODE); @@ -1200,18 +1420,18 @@ static int nsc_fir_dma_receive(struct nsc_fir_cb *self) } /* - * Function nsc_fir_dma_receive_complete (self) + * Function nsc_ircc_dma_receive_complete (self) * * Finished with receiving frames * * */ -static int nsc_fir_dma_receive_complete(struct nsc_fir_cb *self, int iobase) +static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase) { - struct sk_buff *skb; struct st_fifo *st_fifo; - __u8 bank; + struct sk_buff *skb; __u8 status; + __u8 bank; int len; st_fifo = &self->st_fifo; @@ -1219,22 +1439,27 @@ static int nsc_fir_dma_receive_complete(struct nsc_fir_cb *self, int iobase) /* Save current bank */ bank = inb(iobase+BSR); - /* Read status FIFO */ + /* Read all entries in status FIFO */ switch_bank(iobase, BANK5); while ((status = inb(iobase+FRM_ST)) & FRM_ST_VLD) { - st_fifo->entries[st_fifo->tail].status = status; + /* We must empty the status FIFO no matter what */ + len = inb(iobase+RFLFL) | ((inb(iobase+RFLFH) & 0x1f) << 8); - st_fifo->entries[st_fifo->tail].len = inb(iobase+RFLFL); - st_fifo->entries[st_fifo->tail].len |= inb(iobase+RFLFH) << 8; - + if (st_fifo->tail >= MAX_RX_WINDOW) + continue; + + st_fifo->entries[st_fifo->tail].status = status; + st_fifo->entries[st_fifo->tail].len = len; + st_fifo->pending_bytes += len; st_fifo->tail++; st_fifo->len++; } /* Try to process all entries in status FIFO */ - while (st_fifo->len) { + while (st_fifo->len > 0) { /* Get first entry */ status = st_fifo->entries[st_fifo->head].status; len = st_fifo->entries[st_fifo->head].len; + st_fifo->pending_bytes -= len; st_fifo->head++; st_fifo->len--; @@ -1265,36 +1490,46 @@ static int nsc_fir_dma_receive_complete(struct nsc_fir_cb *self, int iobase) if (status & FRM_ST_OVR2) self->stats.rx_fifo_errors++; } else { - /* Check if we have transfered all data to memory */ - switch_bank(iobase, BANK0); - if (inb(iobase+LSR) & LSR_RXDA) { - /* Put this entry back in fifo */ - st_fifo->head--; - st_fifo->len++; - st_fifo->entries[st_fifo->head].status = status; - st_fifo->entries[st_fifo->head].len = len; - - /* Restore bank register */ - outb(bank, iobase+BSR); + /* + * First we must make sure that the frame we + * want to deliver is all in main memory. If we + * cannot tell, then we check if the Rx FIFO is + * empty. If not then we will have to take a nap + * and try again later. + */ + if (st_fifo->pending_bytes < self->io.fifo_size) { + switch_bank(iobase, BANK0); + if (inb(iobase+LSR) & LSR_RXDA) { + /* Put this entry back in fifo */ + st_fifo->head--; + st_fifo->len++; + st_fifo->pending_bytes += len; + st_fifo->entries[st_fifo->head].status = status; + st_fifo->entries[st_fifo->head].len = len; - return FALSE; /* I'll be back! */ + /* Restore bank register */ + outb(bank, iobase+BSR); + + return FALSE; /* I'll be back! */ + } } /* - * Remember when we received this frame, so we can + * Remember the time we received this frame, so we can * reduce the min turn time a bit since we will know * how much time we have used for protocol processing */ - do_gettimeofday(&self->stamp); + get_fast_time(&self->stamp); skb = dev_alloc_skb(len+1); if (skb == NULL) { WARNING(__FUNCTION__ "(), memory squeeze, " "dropping frame.\n"); - + self->stats.rx_dropped++; + /* Restore bank register */ outb(bank, iobase+BSR); - + return FALSE; } @@ -1312,6 +1547,7 @@ static int nsc_fir_dma_receive_complete(struct nsc_fir_cb *self, int iobase) /* Move to next frame */ self->rx_buff.data += len; + self->stats.rx_bytes += len; self->stats.rx_packets++; skb->dev = self->netdev; @@ -1327,21 +1563,17 @@ static int nsc_fir_dma_receive_complete(struct nsc_fir_cb *self, int iobase) } /* - * Function nsc_fir_pio_receive (self) + * Function nsc_ircc_pio_receive (self) * * Receive all data in receiver FIFO * */ -static void nsc_fir_pio_receive(struct nsc_fir_cb *self) +static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self) { - __u8 byte = 0x00; + __u8 byte; int iobase; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - - ASSERT(self != NULL, return;); - - iobase = self->io.iobase; + iobase = self->io.fir_base; /* Receive all characters in Rx FIFO */ do { @@ -1352,20 +1584,19 @@ static void nsc_fir_pio_receive(struct nsc_fir_cb *self) } /* - * Function nsc_fir_sir_interrupt (self, eir) + * Function nsc_ircc_sir_interrupt (self, eir) * * Handle SIR interrupt * */ -static __u8 nsc_fir_sir_interrupt(struct nsc_fir_cb *self, int eir) +static void nsc_ircc_sir_interrupt(struct nsc_ircc_cb *self, int eir) { int actual; - __u8 new_ier = 0; /* Check if transmit FIFO is low on data */ if (eir & EIR_TXLDL_EV) { /* Write data left in transmit buffer */ - actual = nsc_fir_pio_write(self->io.iobase, + actual = nsc_ircc_pio_write(self->io.fir_base, self->tx_buff.data, self->tx_buff.len, self->io.fifo_size); @@ -1376,14 +1607,14 @@ static __u8 nsc_fir_sir_interrupt(struct nsc_fir_cb *self, int eir) /* Check if finished */ if (self->tx_buff.len > 0) - new_ier |= IER_TXLDL_IE; + self->ier = IER_TXLDL_IE; else { self->netdev->tbusy = 0; /* Unlock */ self->stats.tx_packets++; mark_bh(NET_BH); - new_ier |= IER_TXEMP_IE; + self->ier = IER_TXEMP_IE; } } @@ -1392,56 +1623,62 @@ static __u8 nsc_fir_sir_interrupt(struct nsc_fir_cb *self, int eir) /* Check if we need to change the speed? */ if (self->new_speed) { IRDA_DEBUG(2, __FUNCTION__ "(), Changing speed!\n"); - nsc_fir_change_speed(self, self->new_speed); + nsc_ircc_change_speed(self, self->new_speed); self->new_speed = 0; - } + /* Check if we are going to FIR */ + if (self->io.speed > 115200) { + /* Should wait for status FIFO interrupt */ + self->ier = IER_SFIF_IE; + + /* No need to do anymore SIR stuff */ + return; + } + } /* Turn around and get ready to receive some data */ self->io.direction = IO_RECV; - new_ier |= IER_RXHDL_IE; + self->ier = IER_RXHDL_IE; } /* Rx FIFO threshold or timeout */ if (eir & EIR_RXHDL_EV) { - nsc_fir_pio_receive(self); + nsc_ircc_pio_receive(self); /* Keep receiving */ - new_ier |= IER_RXHDL_IE; + self->ier = IER_RXHDL_IE; } - return new_ier; } /* - * Function nsc_fir_fir_interrupt (self, eir) + * Function nsc_ircc_fir_interrupt (self, eir) * * Handle MIR/FIR interrupt * */ -static __u8 nsc_fir_fir_interrupt(struct nsc_fir_cb *self, int iobase, int eir) +static void nsc_ircc_fir_interrupt(struct nsc_ircc_cb *self, int iobase, + int eir) { - __u8 new_ier = 0; __u8 bank; bank = inb(iobase+BSR); - /* Status event, or end of frame detected in FIFO */ - if (eir & (EIR_SFIF_EV|EIR_LS_EV)) { - if (nsc_fir_dma_receive_complete(self, iobase)) { - + /* Status FIFO event*/ + if (eir & EIR_SFIF_EV) { + if (nsc_ircc_dma_receive_complete(self, iobase)) { /* Wait for next status FIFO interrupt */ - new_ier |= IER_SFIF_IE; + self->ier = IER_SFIF_IE; } else { - /* DMA not finished yet */ - - /* Set timer value, resolution 125 us */ + /* + * DMA not finished yet, so try again later, set + * timer value, resolution 125 us + */ switch_bank(iobase, BANK4); - outb(0x0f, iobase+TMRL); /* 125 us * 15 */ + outb(0x02, iobase+TMRL); /* 2 * 125 us */ outb(0x00, iobase+TMRH); /* Start timer */ outb(IRCR1_TMR_EN, iobase+IRCR1); - - new_ier |= IER_TMR_IE; + self->ier = IER_TMR_IE | IER_SFIF_IE; } } else if (eir & EIR_TMR_EV) { /* Timer finished */ /* Disable timer */ @@ -1452,101 +1689,102 @@ static __u8 nsc_fir_fir_interrupt(struct nsc_fir_cb *self, int iobase, int eir) switch_bank(iobase, BANK0); outb(ASCR_CTE, iobase+ASCR); - /* Check if this is a TX timer interrupt */ + /* Check if this is a Tx timer interrupt */ if (self->io.direction == IO_XMIT) { - nsc_fir_dma_xmit(self, iobase); + nsc_ircc_dma_xmit(self, iobase); /* Interrupt on DMA */ - new_ier |= IER_DMA_IE; + self->ier = IER_DMA_IE; } else { /* Check if DMA has now finished */ - nsc_fir_dma_receive_complete(self, iobase); + nsc_ircc_dma_receive_complete(self, iobase); - new_ier |= IER_SFIF_IE; + self->ier = IER_SFIF_IE; } - } else if (eir & EIR_DMA_EV) { /* Finished with transmission */ - if (nsc_fir_dma_xmit_complete(self)) { + } else if (eir & EIR_DMA_EV) { + /* Finished with all transmissions? */ + if (nsc_ircc_dma_xmit_complete(self)) { /* Check if there are more frames to be transmitted */ if (irda_device_txqueue_empty(self->netdev)) { /* Prepare for receive */ - nsc_fir_dma_receive(self); + nsc_ircc_dma_receive(self); - new_ier = IER_LS_IE|IER_SFIF_IE; + self->ier = IER_SFIF_IE; } } else { /* Not finished yet, so interrupt on DMA again */ - new_ier |= IER_DMA_IE; + self->ier = IER_DMA_IE; } } outb(bank, iobase+BSR); - - return new_ier; } /* - * Function nsc_fir_interrupt (irq, dev_id, regs) + * Function nsc_ircc_interrupt (irq, dev_id, regs) * * An interrupt from the chip has arrived. Time to do some work * */ -static void nsc_fir_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void nsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; - struct nsc_fir_cb *self; - __u8 bsr, eir, ier; + struct nsc_ircc_cb *self; + __u8 bsr, eir; int iobase; if (!dev) { - printk(KERN_WARNING "%s: irq %d for unknown device.\n", - driver_name, irq); + WARNING("%s: irq %d for unknown device.\n", driver_name, irq); return; } - self = (struct nsc_fir_cb *) dev->priv; + self = (struct nsc_ircc_cb *) dev->priv; spin_lock(&self->lock); dev->interrupt = 1; - iobase = self->io.iobase; + iobase = self->io.fir_base; bsr = inb(iobase+BSR); /* Save current bank */ switch_bank(iobase, BANK0); - ier = inb(iobase+IER); - eir = inb(iobase+EIR) & ier; /* Mask out the interesting ones */ + self->ier = inb(iobase+IER); + eir = inb(iobase+EIR) & self->ier; /* Mask out the interesting ones */ outb(0, iobase+IER); /* Disable interrupts */ if (eir) { /* Dispatch interrupt handler for the current speed */ if (self->io.speed > 115200) - ier = nsc_fir_fir_interrupt(self, iobase, eir); + nsc_ircc_fir_interrupt(self, iobase, eir); else - ier = nsc_fir_sir_interrupt(self, eir); + nsc_ircc_sir_interrupt(self, eir); } - - outb(ier, iobase+IER); /* Restore interrupts */ - outb(bsr, iobase+BSR); /* Restore bank register */ + + outb(self->ier, iobase+IER); /* Restore interrupts */ + outb(bsr, iobase+BSR); /* Restore bank register */ dev->interrupt = 0; spin_unlock(&self->lock); } /* - * Function nsc_fir_is_receiving (self) + * Function nsc_ircc_is_receiving (self) * * Return TRUE is we are currently receiving a frame * */ -static int nsc_fir_is_receiving(struct nsc_fir_cb *self) +static int nsc_ircc_is_receiving(struct nsc_ircc_cb *self) { + unsigned long flags; int status = FALSE; int iobase; __u8 bank; ASSERT(self != NULL, return FALSE;); + spin_lock_irqsave(&self->lock, flags); + if (self->io.speed > 115200) { - iobase = self->io.iobase; + iobase = self->io.fir_base; /* Check if rx FIFO is not empty */ bank = inb(iobase+BSR); @@ -1559,16 +1797,18 @@ static int nsc_fir_is_receiving(struct nsc_fir_cb *self) } else status = (self->rx_buff.state != OUTSIDE_FRAME); + spin_unlock_irqrestore(&self->lock, flags); + return status; } /* - * Function nsc_fir_net_init (dev) + * Function nsc_ircc_net_init (dev) * * Initialize network device * */ -static int nsc_fir_net_init(struct net_device *dev) +static int nsc_ircc_net_init(struct net_device *dev) { IRDA_DEBUG(4, __FUNCTION__ "()\n"); @@ -1581,29 +1821,29 @@ static int nsc_fir_net_init(struct net_device *dev) } /* - * Function nsc_fir_net_open (dev) + * Function nsc_ircc_net_open (dev) * * Start the device * */ -static int nsc_fir_net_open(struct net_device *dev) +static int nsc_ircc_net_open(struct net_device *dev) { - struct nsc_fir_cb *self; + struct nsc_ircc_cb *self; int iobase; __u8 bank; IRDA_DEBUG(4, __FUNCTION__ "()\n"); ASSERT(dev != NULL, return -1;); - self = (struct nsc_fir_cb *) dev->priv; + self = (struct nsc_ircc_cb *) dev->priv; ASSERT(self != NULL, return 0;); - iobase = self->io.iobase; - - if (request_irq(self->io.irq, nsc_fir_interrupt, 0, dev->name, - (void *) dev)) - { + iobase = self->io.fir_base; + + if (request_irq(self->io.irq, nsc_ircc_interrupt, 0, dev->name, dev)) { + WARNING("%s, unable to allocate irq=%d\n", driver_name, + self->io.irq); return -EAGAIN; } /* @@ -1611,6 +1851,8 @@ static int nsc_fir_net_open(struct net_device *dev) * failure. */ if (request_dma(self->io.dma, dev->name)) { + WARNING("%s, unable to allocate dma=%d\n", driver_name, + self->io.dma); free_irq(self->io.irq, self); return -EAGAIN; } @@ -1642,22 +1884,22 @@ static int nsc_fir_net_open(struct net_device *dev) } /* - * Function nsc_fir_net_close (dev) + * Function nsc_ircc_net_close (dev) * * Stop the device * */ -static int nsc_fir_net_close(struct net_device *dev) +static int nsc_ircc_net_close(struct net_device *dev) { - struct nsc_fir_cb *self; + struct nsc_ircc_cb *self; int iobase; __u8 bank; IRDA_DEBUG(4, __FUNCTION__ "()\n"); ASSERT(dev != NULL, return -1;); - self = (struct nsc_fir_cb *) dev->priv; - + + self = (struct nsc_ircc_cb *) dev->priv; ASSERT(self != NULL, return 0;); /* Stop device */ @@ -1669,7 +1911,7 @@ static int nsc_fir_net_close(struct net_device *dev) irlap_close(self->irlap); self->irlap = NULL; - iobase = self->io.iobase; + iobase = self->io.fir_base; disable_dma(self->io.dma); @@ -1692,15 +1934,15 @@ static int nsc_fir_net_close(struct net_device *dev) } /* - * Function nsc_fir_net_ioctl (dev, rq, cmd) + * Function nsc_ircc_net_ioctl (dev, rq, cmd) * * Process IOCTL commands for this device * */ -static int nsc_fir_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct if_irda_req *irq = (struct if_irda_req *) rq; - struct nsc_fir_cb *self; + struct nsc_ircc_cb *self; unsigned long flags; int ret = 0; @@ -1718,13 +1960,13 @@ static int nsc_fir_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ - nsc_fir_change_speed(self, irq->ifr_baudrate); + nsc_ircc_change_speed(self, irq->ifr_baudrate); break; case SIOCSMEDIABUSY: /* Set media busy */ irda_device_set_media_busy(self->netdev, TRUE); break; case SIOCGRECEIVING: /* Check if we are receiving right now */ - irq->ifr_receiving = nsc_fir_is_receiving(self); + irq->ifr_receiving = nsc_ircc_is_receiving(self); break; default: ret = -EOPNOTSUPP; @@ -1735,54 +1977,60 @@ static int nsc_fir_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return ret; } -static struct net_device_stats *nsc_fir_net_get_stats(struct net_device *dev) +static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev) { - struct nsc_fir_cb *self = (struct nsc_fir_cb *) dev->priv; + struct nsc_ircc_cb *self = (struct nsc_ircc_cb *) dev->priv; return &self->stats; } #ifdef CONFIG_APM -static void nsc_fir_suspend(struct nsc_fir_cb *self) +static void nsc_ircc_suspend(struct nsc_ircc_cb *self) { - int i = 10; - MESSAGE("%s, Suspending\n", driver_name); - if (self->suspend) + if (self->io.suspended) return; - self->suspend = 1; -} + nsc_ircc_net_close(self->netdev); + self->io.suspended = 1; +} -static void nsc_fir_wakeup(struct nsc_fir_cb *self) +static void nsc_ircc_wakeup(struct nsc_ircc_cb *self) { struct net_device *dev = self->netdev; - unsigned long flags; + int iobase; - if (!self->suspend) + if (!self->io.suspended) return; - save_flags(flags); - cli(); + iobase = self->io.fir_base; - restore_flags(flags); + /* Switch to advanced mode */ + switch_bank(iobase, BANK2); + outb(ECR1_EXT_SL, iobase+ECR1); + switch_bank(iobase, BANK0); + + nsc_ircc_net_open(self->netdev); + MESSAGE("%s, Waking up\n", driver_name); + + self->io.suspended = 0; } -static int nsc_fir_apmproc(apm_event_t event) +static int nsc_ircc_apmproc(apm_event_t event) { - static int down = 0; /* Filter out double events */ + static int down = 0; /* Filter out double events */ int i; switch (event) { case APM_SYS_SUSPEND: case APM_USER_SUSPEND: if (!down) { - for (i = 0; i < 4; i++) { + for (i=0; i<4; i++) { if (dev_self[i]) - nsc_fir_suspend(dev_self[i]); + nsc_ircc_suspend(dev_self[i]); } } down = 1; @@ -1790,9 +2038,9 @@ static int nsc_fir_apmproc(apm_event_t event) case APM_NORMAL_RESUME: case APM_CRITICAL_RESUME: if (down) { - for (i = 0; i < 4; i++) { + for (i=0; i<4; i++) { if (dev_self[i]) - nsc_fir_wakeup(dev_self[i]); + nsc_ircc_wakeup(dev_self[i]); } } down = 0; @@ -1804,22 +2052,22 @@ static int nsc_fir_apmproc(apm_event_t event) #ifdef MODULE MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); -MODULE_DESCRIPTION("NSC FIR IrDA Device Driver"); +MODULE_DESCRIPTION("NSC IrDA Device Driver"); MODULE_PARM(qos_mtt_bits, "i"); -MODULE_PARM(io, "1-4i"); -MODULE_PARM(io2, "1-4i"); +MODULE_PARM(io, "1-4i"); MODULE_PARM(irq, "1-4i"); +MODULE_PARM(dma, "1-4i"); MODULE_PARM(dongle_id, "i"); int init_module(void) { - return nsc_fir_init(); + return nsc_ircc_init(); } void cleanup_module(void) { - nsc_fir_cleanup(); + nsc_ircc_cleanup(); } #endif /* MODULE */ diff --git a/drivers/net/irda/smc-ircc.c b/drivers/net/irda/smc-ircc.c index 1d857c2b0..48b38227e 100644 --- a/drivers/net/irda/smc-ircc.c +++ b/drivers/net/irda/smc-ircc.c @@ -1,12 +1,12 @@ /********************************************************************* * * Filename: smc-ircc.c - * Version: 0.3 + * Version: 0.4 * Description: Driver for the SMC Infrared Communications Controller * Status: Experimental. * Author: Thomas Davis (tadavis@jps.net) * Created at: - * Modified at: Wed Jan 5 12:38:06 2000 + * Modified at: Fri Jan 21 09:41:08 2000 * Modified by: Dag Brattli <dagb@cs.uit.no> * * Copyright (c) 1999-2000 Dag Brattli @@ -28,11 +28,12 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * - * SIO's: SMC FDC37N869, FDC37C669 + * SIO's: SMC FDC37N869, FDC37C669, FDC37N958 * Applicable Models : Fujitsu Lifebook 635t, Sony PCG-505TX * ********************************************************************/ +#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> @@ -44,11 +45,16 @@ #include <linux/malloc.h> #include <linux/init.h> #include <linux/rtnetlink.h> +#include <linux/serial_reg.h> #include <asm/io.h> #include <asm/dma.h> #include <asm/byteorder.h> +#ifdef CONFIG_APM +#include <linux/apm_bios.h> +#endif + #include <net/irda/wrapper.h> #include <net/irda/irda.h> #include <net/irda/irmod.h> @@ -62,10 +68,10 @@ static char *driver_name = "smc-ircc"; #define CHIP_IO_EXTENT 8 -static unsigned int io[] = { 0x2e8, 0x140, 0x118, 0x240 }; -static unsigned int io2[] = { 0x2f8, 0x3e8, 0x2e8, 0x3e8 }; +static unsigned int io[] = { ~0, ~0 }; +static unsigned int io2[] = { 0, 0 }; -static struct ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL}; +static struct ircc_cb *dev_self[] = { NULL, NULL}; /* Some prototypes */ static int ircc_open(int i, unsigned int iobase, unsigned int board_addr); @@ -73,17 +79,30 @@ static int ircc_open(int i, unsigned int iobase, unsigned int board_addr); static int ircc_close(struct ircc_cb *self); #endif /* MODULE */ static int ircc_probe(int iobase, int board_addr); -static int ircc_probe_smc(int *ioaddr, int *ioaddr2); -static int ircc_dma_receive(struct ircc_cb *self); -static int ircc_dma_receive_complete(struct ircc_cb *self, int iobase); +static int ircc_probe_58(smc_chip_t *chip, chipio_t *info); +static int ircc_probe_69(smc_chip_t *chip, chipio_t *info); +static int ircc_dma_receive(struct ircc_cb *self, int iobase); +static void ircc_dma_receive_complete(struct ircc_cb *self, int iobase); static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev); -static void ircc_dma_xmit(struct ircc_cb *self, int iobase); +static void ircc_dma_xmit(struct ircc_cb *self, int iobase, int bofs); static void ircc_change_speed(void *priv, __u32 speed); static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs); static int ircc_is_receiving(struct ircc_cb *self); static int ircc_net_open(struct net_device *dev); static int ircc_net_close(struct net_device *dev); +#ifdef CONFIG_APM +static int ircc_apmproc(apm_event_t event); +#endif /* CONFIG_APM */ + +/* These are the currently known SMC chipsets */ +static smc_chip_t chips[] = +{ + { "FDC37C669", 0x55, 0x55, 0x0d, 0x04, ircc_probe_69 }, + { "FDC37N869", 0x55, 0x00, 0x0d, 0x29, ircc_probe_69 }, + { "FDC37N958", 0x55, 0x55, 0x20, 0x09, ircc_probe_58 }, + { NULL } +}; static int ircc_irq=255; static int ircc_dma=255; @@ -102,26 +121,38 @@ static inline void register_bank(int iobase, int bank) */ int __init ircc_init(void) { - int ioaddr, ioaddr2; + static int smcreg[] = { 0x3f0, 0x370 }; + smc_chip_t *chip; + chipio_t info; + int ret = -ENODEV; int i; IRDA_DEBUG(0, __FUNCTION__ "\n"); - for (i=0; (io[i] < 2000) && (i < 4); i++) { - int ioaddr = io[i]; - if (check_region(ioaddr, CHIP_IO_EXTENT)) - continue; - if (ircc_open(i, io[i], io2[i]) == 0) - return 0; - } - /* last chance saloon, see what the controller says */ - if (ircc_probe_smc(&ioaddr, &ioaddr2) == 0) { - if (check_region(ioaddr, CHIP_IO_EXTENT) == 0) - if (ircc_open(0, ioaddr, ioaddr2) == 0) - return 0; + /* Probe for all the NSC chipsets we know about */ + for (chip=chips; chip->name ; chip++,i++) { + for (i=0; i<2; i++) { + info.cfg_base = smcreg[i]; + + /* + * First we check if the user has supplied any + * parameters which we should use instead of probed + * values + */ + if (io[i] < 2000) { + info.fir_base = io[i]; + info.sir_base = io2[i]; + } else if (chip->probe(chip, &info) < 0) + continue; + if (check_region(info.fir_base, CHIP_IO_EXTENT) < 0) + continue; + if (check_region(info.sir_base, CHIP_IO_EXTENT) < 0) + continue; + if (ircc_open(i, info.fir_base, info.sir_base) == 0) + ret = 0; + } } - - return -ENODEV; + return ret; } /* @@ -137,7 +168,7 @@ static void ircc_cleanup(void) IRDA_DEBUG(0, __FUNCTION__ "\n"); - for (i=0; i < 4; i++) { + for (i=0; i < 2; i++) { if (dev_self[i]) ircc_close(dev_self[i]); } @@ -150,7 +181,7 @@ static void ircc_cleanup(void) * Open driver instance * */ -static int ircc_open(int i, unsigned int iobase, unsigned int iobase2) +static int ircc_open(int i, unsigned int fir_base, unsigned int sir_base) { struct ircc_cb *self; struct irport_cb *irport; @@ -159,9 +190,9 @@ static int ircc_open(int i, unsigned int iobase, unsigned int iobase2) IRDA_DEBUG(0, __FUNCTION__ "\n"); - if ((config = ircc_probe(iobase, iobase2)) == -1) { + if ((config = ircc_probe(fir_base, sir_base)) == -1) { IRDA_DEBUG(0, __FUNCTION__ - "(), addr 0x%04x - no device found!\n", iobase); + "(), addr 0x%04x - no device found!\n", fir_base); return -1; } @@ -180,7 +211,7 @@ static int ircc_open(int i, unsigned int iobase, unsigned int iobase2) /* Need to store self somewhere */ dev_self[i] = self; - irport = irport_open(0, iobase2, config >> 4 & 0x0f); + irport = irport_open(i, sir_base, config >> 4 & 0x0f); if (!irport) return -ENODEV; @@ -190,34 +221,32 @@ static int ircc_open(int i, unsigned int iobase, unsigned int iobase2) irport->priv = self; /* Initialize IO */ - self->io.iobase = iobase; - self->io.iobase2 = iobase2; /* Used by irport */ + self->io.fir_base = fir_base; + self->io.sir_base = sir_base; /* Used by irport */ self->io.irq = config >> 4 & 0x0f; if (ircc_irq < 255) { MESSAGE("%s, Overriding IRQ - chip says %d, using %d\n", driver_name, self->io.irq, ircc_irq); self->io.irq = ircc_irq; } - self->io.io_ext = CHIP_IO_EXTENT; - self->io.io_ext2 = 8; /* Used by irport */ + self->io.fir_ext = CHIP_IO_EXTENT; + self->io.sir_ext = 8; /* Used by irport */ self->io.dma = config & 0x0f; if (ircc_dma < 255) { MESSAGE("%s, Overriding DMA - chip says %d, using %d\n", driver_name, self->io.dma, ircc_dma); self->io.dma = ircc_dma; } - self->io.fifo_size = 16; /* Lock the port that we need */ - ret = check_region(self->io.iobase, self->io.io_ext); + ret = check_region(self->io.fir_base, self->io.fir_ext); if (ret < 0) { - IRDA_DEBUG(0, __FUNCTION__ ": can't get iobase of 0x%03x\n", - self->io.iobase); - /* ircc_cleanup(self->self); */ + IRDA_DEBUG(0, __FUNCTION__ ": can't get fir_base of 0x%03x\n", + self->io.fir_base); + kfree(self); return -ENODEV; } - - request_region(self->io.iobase, self->io.io_ext, driver_name); + request_region(self->io.fir_base, self->io.fir_ext, driver_name); /* Initialize QoS for this device */ irda_init_max_qos_capabilies(&irport->qos); @@ -229,7 +258,7 @@ static int ircc_open(int i, unsigned int iobase, unsigned int iobase2) irport->qos.min_turn_time.bits = 0x07; irda_qos_bits_to_value(&irport->qos); - irport->flags = IFF_FIR|IFF_SIR|IFF_DMA|IFF_PIO; + irport->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO; /* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */ self->rx_buff.truesize = 4000; @@ -256,6 +285,7 @@ static int ircc_open(int i, unsigned int iobase, unsigned int iobase2) /* Override the speed change function, since we must control it now */ irport->change_speed = &ircc_change_speed; + irport->interrupt = &ircc_interrupt; self->netdev->open = &ircc_net_open; self->netdev->stop = &ircc_net_close; @@ -279,23 +309,26 @@ static int ircc_close(struct ircc_cb *self) ASSERT(self != NULL, return -1;); - iobase = self->io.iobase; + iobase = self->io.fir_base; irport_close(self->irport); + /* Stop interrupts */ register_bank(iobase, 0); outb(0, iobase+IRCC_IER); outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER); - + outb(0x00, iobase+IRCC_MASTER); +#if 0 + /* Reset to SIR mode */ register_bank(iobase, 1); - outb(IRCC_CFGA_IRDA_SIR_A|IRCC_CFGA_TX_POLARITY, iobase+IRCC_SCE_CFGA); outb(IRCC_CFGB_IR, iobase+IRCC_SCE_CFGB); - +#endif /* Release the PORT that this driver is using */ - IRDA_DEBUG(0, __FUNCTION__ "(), releasing 0x%03x\n", self->io.iobase); + IRDA_DEBUG(0, __FUNCTION__ "(), releasing 0x%03x\n", + self->io.fir_base); - release_region(self->io.iobase, self->io.io_ext); + release_region(self->io.fir_base, self->io.fir_ext); if (self->tx_buff.head) kfree(self->tx_buff.head); @@ -310,58 +343,106 @@ static int ircc_close(struct ircc_cb *self) #endif /* MODULE */ /* - * Function ircc_probe_smc (ioaddr, ioaddr2) + * Function ircc_probe_69 (chip, info) * - * Probe the SMC Chip for an IrDA port + * Probes for the SMC FDC37C669 and FDC37N869 * */ -static int ircc_probe_smc(int *ioaddr, int *ioaddr2) +static int ircc_probe_69(smc_chip_t *chip, chipio_t *info) { - static int smcreg[] = { 0x3f0, 0x370 }; + int cfg_base = info->cfg_base; __u8 devid, mode; - __u8 conf_reg; - int ret = -1; + int ret = -ENODEV; int fir_io; - int i; IRDA_DEBUG(0, __FUNCTION__ "()\n"); - for (i = 0; i < 2 && ret == -1; i++) { - conf_reg = smcreg[i]; - - /* Enter configuration */ - outb(0x55, conf_reg); - outb(0x55, conf_reg); - - outb(0x0d, conf_reg); - devid = inb(conf_reg+1); - IRDA_DEBUG(0, __FUNCTION__ "(), devid=0x%02x\n",devid); + /* Enter configuration */ + outb(chip->entr1, cfg_base); + outb(chip->entr2, cfg_base); + + outb(chip->cid_index, cfg_base); + devid = inb(cfg_base+1); + IRDA_DEBUG(0, __FUNCTION__ "(), devid=0x%02x\n",devid); + + /* Check for expected device ID; are there others? */ + if (devid == chip->cid_value) { + outb(0x0c, cfg_base); + mode = inb(cfg_base+1); + mode = (mode & 0x38) >> 3; - /* Check for expected device ID; are there others? */ - if (devid == 0x29) { - outb(0x0c, conf_reg); - mode = inb(conf_reg+1); - mode = (mode & 0x38) >> 3; - - /* Value for IR port */ - if (mode && mode < 4) { - /* SIR iobase */ - outb(0x25, conf_reg); - *ioaddr2 = inb(conf_reg+1) << 2; - - /* FIR iobase */ - outb(0x2b, conf_reg); - fir_io = inb(conf_reg+1) << 3; - if (fir_io) { - ret = 0; - *ioaddr = fir_io; - } + /* Value for IR port */ + if (mode && mode < 4) { + /* SIR iobase */ + outb(0x25, cfg_base); + info->sir_base = inb(cfg_base+1) << 2; + + /* FIR iobase */ + outb(0x2b, cfg_base); + fir_io = inb(cfg_base+1) << 3; + if (fir_io) { + ret = 0; + info->fir_base = fir_io; } } + } + + /* Exit configuration */ + outb(0xaa, cfg_base); + + return ret; +} + +/* + * Function ircc_probe_58 (chip, info) + * + * Probes for the SMC FDC37N958 + * + */ +static int ircc_probe_58(smc_chip_t *chip, chipio_t *info) +{ + int cfg_base = info->cfg_base; + __u8 devid; + int ret = -ENODEV; + int fir_io; + + IRDA_DEBUG(0, __FUNCTION__ "()\n"); + + /* Enter configuration */ + outb(chip->entr1, cfg_base); + outb(chip->entr2, cfg_base); + + outb(chip->cid_index, cfg_base); + devid = inb(cfg_base+1); + IRDA_DEBUG(0, __FUNCTION__ "(), devid=0x%02x\n",devid); + + /* Check for expected device ID; are there others? */ + if (devid == chip->cid_value) { + /* Select logical device (UART2) */ + outb(0x07, cfg_base); + outb(0x05, cfg_base + 1); + + /* SIR iobase */ + outb(0x60, cfg_base); + info->sir_base = inb(cfg_base + 1) << 8; + outb(0x61, cfg_base); + info->sir_base |= inb(cfg_base + 1); + + /* Read FIR base */ + outb(0x62, cfg_base); + fir_io = inb(cfg_base + 1) << 8; + outb(0x63, cfg_base); + fir_io |= inb(cfg_base + 1); + outb(0x2b, cfg_base); + if (fir_io) { + ret = 0; + info->fir_base = fir_io; + } + } + + /* Exit configuration */ + outb(0xaa, cfg_base); - /* Exit configuration */ - outb(0xaa, conf_reg); - } return ret; } @@ -371,34 +452,32 @@ static int ircc_probe_smc(int *ioaddr, int *ioaddr2) * Returns non-negative on success. * */ -static int ircc_probe(int iobase, int iobase2) +static int ircc_probe(int fir_base, int sir_base) { - int version = 1; int low, high, chip, config, dma, irq; - - IRDA_DEBUG(0, __FUNCTION__ "\n"); + int iobase = fir_base; + int version = 1; - /* Power on device */ - outb(inb(iobase+IRCC_MASTER) & ~IRCC_MASTER_POWERDOWN, - iobase+IRCC_MASTER); + IRDA_DEBUG(0, __FUNCTION__ "\n"); register_bank(iobase, 3); - high = inb(iobase+IRCC_ID_HIGH); - low = inb(iobase+IRCC_ID_LOW); - chip = inb(iobase+IRCC_CHIP_ID); + high = inb(iobase+IRCC_ID_HIGH); + low = inb(iobase+IRCC_ID_LOW); + chip = inb(iobase+IRCC_CHIP_ID); version = inb(iobase+IRCC_VERSION); - config = inb(iobase+IRCC_INTERFACE); - irq = config >> 4 & 0x0f; - dma = config & 0x0f; + config = inb(iobase+IRCC_INTERFACE); + irq = config >> 4 & 0x0f; + dma = config & 0x0f; if (high == 0x10 && low == 0xb8 && (chip == 0xf1 || chip == 0xf2)) { - IRDA_DEBUG(0, "SMC IrDA Controller found; IrCC version %d.%d, " - "port 0x%04x, dma %d, interrupt %d\n", - chip & 0x0f, version, iobase, dma, irq); + MESSAGE("SMC IrDA Controller found; IrCC version %d.%d, " + "port 0x%03x, dma=%d, irq=%d\n", + chip & 0x0f, version, iobase, dma, irq); } else - return -1; + return -ENODEV; - outb(0, iobase+IRCC_MASTER); + /* Power on device */ + outb(0x00, iobase+IRCC_MASTER); return config; } @@ -411,7 +490,7 @@ static int ircc_probe(int iobase, int iobase2) */ static void ircc_change_speed(void *priv, __u32 speed) { - int iobase, ir_mode, select, fast; + int iobase, ir_mode, ctrl, fast; struct ircc_cb *self = (struct ircc_cb *) priv; struct net_device *dev; @@ -420,49 +499,39 @@ static void ircc_change_speed(void *priv, __u32 speed) ASSERT(self != NULL, return;); dev = self->netdev; - iobase = self->io.iobase; + iobase = self->io.fir_base; /* Update accounting for new speed */ self->io.speed = speed; + outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER); + outb(0x00, iobase+IRCC_MASTER); + switch (speed) { case 9600: case 19200: case 38400: case 57600: - case 115200: - IRDA_DEBUG(0, __FUNCTION__ - "(), using irport to change speed to %d\n", speed); - - register_bank(iobase, 0); - outb(0, iobase+IRCC_IER); - outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER); - outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER); - - dev->hard_start_xmit = &irport_hard_xmit; - - /* We must give the interrupt back to irport */ - self->irport->interrupt = irport_interrupt; - - irport_start(self->irport); - irport_change_speed(self->irport, speed); - return; + case 115200: + ir_mode = IRCC_CFGA_IRDA_SIR_A; + ctrl = 0; + fast = 0; break; case 576000: ir_mode = IRCC_CFGA_IRDA_HDLC; - select = 0; + ctrl = IRCC_CRC; fast = 0; IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 576000\n"); break; case 1152000: ir_mode = IRCC_CFGA_IRDA_HDLC; - select = IRCC_1152; + ctrl = IRCC_1152 | IRCC_CRC; fast = 0; IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n"); break; case 4000000: ir_mode = IRCC_CFGA_IRDA_4PPM; - select = 0; + ctrl = IRCC_CRC; fast = IRCC_LCR_A_FAST; IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 4000000\n"); break; @@ -471,39 +540,55 @@ static void ircc_change_speed(void *priv, __u32 speed) speed); return; } - - outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER); - + register_bank(iobase, 0); outb(0, iobase+IRCC_IER); - - irport_stop(self->irport); + outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER); + + /* Make special FIR init if necessary */ + if (speed > 115200) { + irport_stop(self->irport); - /* Install FIR transmit handler */ - dev->hard_start_xmit = &ircc_hard_xmit; + /* Install FIR transmit handler */ + dev->hard_start_xmit = &ircc_hard_xmit; - /* Need to steal the interrupt as well */ - self->irport->interrupt = &ircc_interrupt; + /* + * Don't know why we have to do this, but FIR interrupts + * stops working if we remove it. + */ + /* outb(UART_MCR_OUT2, self->io.sir_base + UART_MCR); */ + /* Be ready for incomming frames */ + ircc_dma_receive(self, iobase); + } else { + /* Install SIR transmit handler */ + dev->hard_start_xmit = &irport_hard_xmit; + irport_start(self->irport); + + IRDA_DEBUG(0, __FUNCTION__ + "(), using irport to change speed to %d\n", speed); + irport_change_speed(self->irport, speed); + } dev->tbusy = 0; - + register_bank(iobase, 1); outb(((inb(iobase+IRCC_SCE_CFGA) & 0x87) | ir_mode), iobase+IRCC_SCE_CFGA); - - outb(((inb(iobase+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_IR), - iobase+IRCC_SCE_CFGB); +#ifdef SMC_669 /* Uses pin 88/89 for Rx/Tx */ + outb(((inb(iobase+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM), + iobase+IRCC_SCE_CFGB); +#else + outb(((inb(iobase+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR), + iobase+IRCC_SCE_CFGB); +#endif (void) inb(iobase+IRCC_FIFO_THRESHOLD); outb(64, iobase+IRCC_FIFO_THRESHOLD); - + register_bank(iobase, 4); - - outb((inb(iobase+IRCC_CONTROL) & 0x30) | select | IRCC_CRC, - iobase+IRCC_CONTROL); - + outb((inb(iobase+IRCC_CONTROL) & 0x30) | ctrl, iobase+IRCC_CONTROL); + register_bank(iobase, 0); - outb(fast, iobase+IRCC_LCR_A); } @@ -517,21 +602,20 @@ static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev) { struct irport_cb *irport; struct ircc_cb *self; + unsigned long flags; + __u32 speed; int iobase; int mtt; - __u32 speed; irport = (struct irport_cb *) dev->priv; self = (struct ircc_cb *) irport->priv; - ASSERT(self != NULL, return 0;); - iobase = self->io.iobase; + iobase = self->io.fir_base; - IRDA_DEBUG(2, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies, - (int) skb->len); + spin_lock_irqsave(&self->lock, flags); - /* Check if we need to change the speed */ + /* Check if we need to change the speed after this frame */ if ((speed = irda_get_speed(skb)) != self->io.speed) self->new_speed = speed; @@ -541,19 +625,28 @@ static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev) memcpy(self->tx_buff.head, skb->data, skb->len); - /* Make sure that the length is a multiple of 16 bits */ - if (skb->len & 0x01) - skb->len++; - self->tx_buff.len = skb->len; self->tx_buff.data = self->tx_buff.head; mtt = irda_get_mtt(skb); - if (mtt) - udelay(mtt); - - ircc_dma_xmit(self, iobase); + if (mtt) { + int bofs; + + /* + * Compute who many BOFS (STA or PA's) we need to waste the + * min turn time given the speed of the link. + */ + bofs = mtt * (self->io.speed / 1000) / 8000; + if (bofs > 4095) + bofs = 4095; + + ircc_dma_xmit(self, iobase, bofs); + } else { + /* Transmit frame */ + ircc_dma_xmit(self, iobase, 0); + } + spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); return 0; @@ -565,44 +658,49 @@ static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev) * Transmit data using DMA * */ -static void ircc_dma_xmit(struct ircc_cb *self, int iobase) +static void ircc_dma_xmit(struct ircc_cb *self, int iobase, int bofs) { - IRDA_DEBUG(2, __FUNCTION__ "\n"); + __u8 ctrl; - ASSERT(self != NULL, return;); - - iobase = self->io.iobase; + IRDA_DEBUG(2, __FUNCTION__ "\n"); +#if 0 + /* Disable Rx */ + register_bank(iobase, 0); + outb(0x00, iobase+IRCC_LCR_B); +#endif + register_bank(iobase, 1); + outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, + iobase+IRCC_SCE_CFGB); - setup_dma(self->io.dma, self->tx_buff.data, self->tx_buff.len, - DMA_TX_MODE); - self->io.direction = IO_XMIT; - outb(0x08, self->io.iobase2+4); - + /* Set BOF additional count for generating the min turn time */ register_bank(iobase, 4); - outb((inb(iobase+IRCC_CONTROL) & 0xf0), iobase+IRCC_CONTROL); - - outb(2, iobase+IRCC_BOF_COUNT_LO); - outb(0, iobase+IRCC_BRICKWALL_CNT_LO); -#if 1 - outb(self->tx_buff.len >> 8, iobase+IRCC_BRICKWALL_TX_CNT_HI); + outb(bofs & 0xff, iobase+IRCC_BOF_COUNT_LO); + ctrl = inb(iobase+IRCC_CONTROL) & 0xf0; + outb(ctrl | ((bofs >> 8) & 0x0f), iobase+IRCC_BOF_COUNT_HI); + + /* Set max Tx frame size */ + outb(self->tx_buff.len >> 8, iobase+IRCC_TX_SIZE_HI); outb(self->tx_buff.len & 0xff, iobase+IRCC_TX_SIZE_LO); -#else - outb(0, iobase+IRCC_BRICKWALL_TX_CNT_HI); - outb(0, iobase+IRCC_TX_SIZE_LO); -#endif + /* Setup DMA controller (must be done after enabling chip DMA) */ + setup_dma(self->io.dma, self->tx_buff.data, self->tx_buff.len, + DMA_TX_MODE); + + outb(UART_MCR_OUT2, self->io.sir_base + UART_MCR); + /* Enable burst mode chip Tx DMA */ register_bank(iobase, 1); - outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE, - iobase+IRCC_SCE_CFGB); + outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE | + IRCC_CFGB_DMA_BURST, iobase+IRCC_SCE_CFGB); + /* Enable interrupt */ + outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER); register_bank(iobase, 0); - outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase+IRCC_IER); - outb(IRCC_LCR_B_SCE_TRANSMIT|IRCC_LCR_B_SIP_ENABLE, iobase+IRCC_LCR_B); - outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER); + /* Enable transmit */ + outb(IRCC_LCR_B_SCE_TRANSMIT|IRCC_LCR_B_SIP_ENABLE, iobase+IRCC_LCR_B); } /* @@ -612,39 +710,36 @@ static void ircc_dma_xmit(struct ircc_cb *self, int iobase) * by the interrupt handler * */ -static void ircc_dma_xmit_complete(struct ircc_cb *self, int underrun) +static void ircc_dma_xmit_complete(struct ircc_cb *self, int iobase) { - int iobase, d; - IRDA_DEBUG(2, __FUNCTION__ "\n"); - - ASSERT(self != NULL, return;); - - register_bank(self->io.iobase, 1); - - outb(inb(self->io.iobase+IRCC_SCE_CFGB) & IRCC_CFGB_DMA_ENABLE, - self->io.iobase+IRCC_SCE_CFGB); - - d = get_dma_residue(self->io.dma); - - IRDA_DEBUG(0, __FUNCTION__ - ": dma residue = %d, len=%d, sent=%d\n", - d, self->tx_buff.len, self->tx_buff.len - d); - - iobase = self->io.iobase; +#if 0 + /* Disable Tx */ + register_bank(iobase, 0); + outb(0x00, iobase+IRCC_LCR_B); +#endif + register_bank(self->io.fir_base, 1); + outb(inb(self->io.fir_base+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, + self->io.fir_base+IRCC_SCE_CFGB); /* Check for underrrun! */ - if (underrun) { + register_bank(iobase, 0); + if (inb(iobase+IRCC_LSR) & IRCC_LSR_UNDERRUN) { self->irport->stats.tx_errors++; - self->irport->stats.tx_fifo_errors++; + self->irport->stats.tx_fifo_errors++; + + /* Reset error condition */ + register_bank(iobase, 0); + outb(IRCC_MASTER_ERROR_RESET, iobase+IRCC_MASTER); + outb(0x00, iobase+IRCC_MASTER); } else { self->irport->stats.tx_packets++; self->irport->stats.tx_bytes += self->tx_buff.len; } + /* Check if it's time to change the speed */ if (self->new_speed) { - ircc_change_speed(self, self->new_speed); - + ircc_change_speed(self, self->new_speed); self->new_speed = 0; } @@ -662,39 +757,31 @@ static void ircc_dma_xmit_complete(struct ircc_cb *self, int underrun) * if it starts to receive a frame. * */ -static int ircc_dma_receive(struct ircc_cb *self) -{ - int iobase; - - IRDA_DEBUG(2, __FUNCTION__ "\n"); - - ASSERT(self != NULL, return -1;); - - iobase= self->io.iobase; +static int ircc_dma_receive(struct ircc_cb *self, int iobase) +{ + /* Turn off chip DMA */ + //register_bank(iobase, 1); + //outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, + // iobase+IRCC_SCE_CFGB); setup_dma(self->io.dma, self->rx_buff.data, self->rx_buff.truesize, - DMA_RX_MODE); - - /* driver->media_busy = FALSE; */ + DMA_RX_MODE); + /* Set max Rx frame size */ + register_bank(iobase, 4); + outb((2050 >> 8) & 0x0f, iobase+IRCC_RX_SIZE_HI); + outb(2050 & 0xff, iobase+IRCC_RX_SIZE_LO); + self->io.direction = IO_RECV; self->rx_buff.data = self->rx_buff.head; -#if 0 - self->rx_buff.offset = 0; -#endif - - register_bank(iobase, 4); - outb(inb(iobase+IRCC_CONTROL) & 0xf0, iobase+IRCC_CONTROL); - outb(2, iobase+IRCC_BOF_COUNT_LO); - outb(0, iobase+IRCC_BRICKWALL_CNT_LO); - outb(0, iobase+IRCC_BRICKWALL_TX_CNT_HI); - outb(0, iobase+IRCC_TX_SIZE_LO); - outb(0, iobase+IRCC_RX_SIZE_HI); - outb(0, iobase+IRCC_RX_SIZE_LO); + /* Setup DMA controller */ + + /* Enable receiver */ register_bank(iobase, 0); outb(IRCC_LCR_B_SCE_RECEIVE | IRCC_LCR_B_SIP_ENABLE, iobase+IRCC_LCR_B); + /* Enable burst mode chip Rx DMA */ register_bank(iobase, 1); outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE | IRCC_CFGB_DMA_BURST, iobase+IRCC_SCE_CFGB); @@ -709,45 +796,54 @@ static int ircc_dma_receive(struct ircc_cb *self) * * */ -static int ircc_dma_receive_complete(struct ircc_cb *self, int iobase) +static void ircc_dma_receive_complete(struct ircc_cb *self, int iobase) { + unsigned long flags; struct sk_buff *skb; int len, msgcnt; IRDA_DEBUG(2, __FUNCTION__ "\n"); +#if 0 + /* Disable Rx */ + register_bank(iobase, 0); + outb(0x00, iobase+IRCC_LCR_B); +#endif + register_bank(iobase, 0); + msgcnt = inb(iobase+IRCC_LCR_B) & 0x08; - msgcnt = inb(self->io.iobase+IRCC_LCR_B) & 0x08; - - IRDA_DEBUG(0, __FUNCTION__ ": dma count = %d\n", + IRDA_DEBUG(2, __FUNCTION__ ": dma count = %d\n", get_dma_residue(self->io.dma)); - len = self->rx_buff.truesize - get_dma_residue(self->io.dma) - 4; - - IRDA_DEBUG(0, __FUNCTION__ ": msgcnt = %d, len=%d\n", msgcnt, len); + len = self->rx_buff.truesize - get_dma_residue(self->io.dma); + + /* Remove CRC */ + if (self->io.speed < 4000000) + len -= 2; + else + len -= 4; + + if ((len < 2) && (len > 2050)) { + WARNING(__FUNCTION__ "(), bogus len=%d\n", len); + return; + } + IRDA_DEBUG(2, __FUNCTION__ ": msgcnt = %d, len=%d\n", msgcnt, len); skb = dev_alloc_skb(len+1); if (!skb) { WARNING(__FUNCTION__ "(), memory squeeze, dropping frame.\n"); - return FALSE; - } - + return; + } /* Make sure IP header gets aligned */ skb_reserve(skb, 1); - skb_put(skb, len); - memcpy(skb->data, self->rx_buff.data, len); + memcpy(skb_put(skb, len), self->rx_buff.data, len); self->irport->stats.rx_packets++; + self->irport->stats.rx_bytes += len; skb->dev = self->netdev; skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); - - register_bank(self->io.iobase, 1); - outb(inb(self->io.iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, - self->io.iobase+IRCC_SCE_CFGB); - - return TRUE; } /* @@ -758,58 +854,54 @@ static int ircc_dma_receive_complete(struct ircc_cb *self, int iobase) */ static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - int iobase, iir; struct net_device *dev = (struct net_device *) dev_id; + struct irport_cb *irport; struct ircc_cb *self; + int iobase, iir; if (dev == NULL) { printk(KERN_WARNING "%s: irq %d for unknown device.\n", driver_name, irq); return; } - - self = (struct ircc_cb *) dev->priv; + irport = (struct irport_cb *) dev->priv; + ASSERT(irport != NULL, return;); + self = (struct ircc_cb *) irport->priv; + ASSERT(self != NULL, return;); - iobase = self->io.iobase; + /* Check if we should use the SIR interrupt handler */ + if (self->io.speed < 576000) { + irport_interrupt(irq, dev_id, regs); + return; + } + iobase = self->io.fir_base; + spin_lock(&self->lock); dev->interrupt = 1; - outb(0, iobase+IRCC_MASTER); - register_bank(iobase, 0); iir = inb(iobase+IRCC_IIR); /* Disable interrupts */ outb(0, iobase+IRCC_IER); - IRDA_DEBUG(0, __FUNCTION__ "(), iir = 0x%02x\n", iir); + IRDA_DEBUG(2, __FUNCTION__ "(), iir = 0x%02x\n", iir); if (iir & IRCC_IIR_EOM) { - IRDA_DEBUG(0, __FUNCTION__ "(), IRCC_IIR_EOM\n"); - if (self->io.direction == IO_RECV) ircc_dma_receive_complete(self, iobase); else ircc_dma_xmit_complete(self, iobase); - ircc_dma_receive(self); - } - if (iir & IRCC_IIR_ACTIVE_FRAME) { - IRDA_DEBUG(0, __FUNCTION__ "(), IRCC_IIR_ACTIVE_FRAME\n"); - self->rx_buff.state = INSIDE_FRAME; -#if 0 - ircc_dma_receive(self); -#endif - } - if (iir & IRCC_IIR_RAW_MODE) { - IRDA_DEBUG(0, __FUNCTION__ "(), IIR RAW mode interrupt.\n"); + ircc_dma_receive(self, iobase); } + /* Enable interrupts again */ register_bank(iobase, 0); outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, iobase+IRCC_IER); - outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER); dev->interrupt = 0; + spin_unlock(&self->lock); } /* @@ -855,7 +947,7 @@ static int ircc_net_open(struct net_device *dev) ASSERT(self != NULL, return 0;); - iobase = self->io.iobase; + iobase = self->io.fir_base; irport_net_open(dev); /* irport allocates the irq */ @@ -894,7 +986,7 @@ static int ircc_net_close(struct net_device *dev) ASSERT(self != NULL, return 0;); - iobase = self->io.iobase; + iobase = self->io.fir_base; irport_net_close(dev); @@ -907,6 +999,69 @@ static int ircc_net_close(struct net_device *dev) return 0; } +#ifdef CONFIG_APM +static void ircc_suspend(struct ircc_cb *self) +{ + int i = 10; + + MESSAGE("%s, Suspending\n", driver_name); + + if (self->io.suspended) + return; + + ircc_net_close(self->netdev); + + self->io.suspended = 1; +} + +static void ircc_wakeup(struct ircc_cb *self) +{ + struct net_device *dev = self->netdev; + unsigned long flags; + + if (!self->io.suspended) + return; + + save_flags(flags); + cli(); + + ircc_net_open(self->netdev); + + restore_flags(flags); + MESSAGE("%s, Waking up\n", driver_name); +} + +static int ircc_apmproc(apm_event_t event) +{ + static int down = 0; /* Filter out double events */ + int i; + + switch (event) { + case APM_SYS_SUSPEND: + case APM_USER_SUSPEND: + if (!down) { + for (i=0; i<4; i++) { + if (dev_self[i]) + ircc_suspend(dev_self[i]); + } + } + down = 1; + break; + case APM_NORMAL_RESUME: + case APM_CRITICAL_RESUME: + if (down) { + for (i=0; i<4; i++) { + if (dev_self[i]) + ircc_wakeup(dev_self[i]); + } + } + down = 0; + break; + } + return 0; +} +#endif /* CONFIG_APM */ + #ifdef MODULE MODULE_AUTHOR("Thomas Davis <tadavis@jps.net>"); MODULE_DESCRIPTION("SMC IrCC controller driver"); diff --git a/drivers/net/irda/toshoboe.c b/drivers/net/irda/toshoboe.c index cbf06af5f..a7b97af37 100644 --- a/drivers/net/irda/toshoboe.c +++ b/drivers/net/irda/toshoboe.c @@ -32,37 +32,6 @@ static char *rcsid = "$Id: toshoboe.c,v 1.91 1999/06/29 14:21:06 root Exp $"; -/* - * $Log: toshoboe.c,v $ - * Revision 1.9 1999/06/29 14:21:06 root - * *** empty log message *** - * - * Revision 1.8 1999/06/29 14:15:08 root - * *** empty log message *** - * - * Revision 1.7 1999/06/29 13:46:42 root - * *** empty log message *** - * - * Revision 1.6 1999/06/29 12:31:03 root - * *** empty log message *** - * - * Revision 1.5 1999/05/12 12:24:39 root - * *** empty log message *** - * - * Revision 1.4 1999/05/12 11:55:08 root - * *** empty log message *** - * - * Revision 1.3 1999/05/09 01:33:12 root - * *** empty log message *** - * - * Revision 1.2 1999/05/09 01:30:38 root - * *** empty log message *** - * - * Revision 1.1 1999/05/09 01:25:04 root - * Initial revision - * - */ - /* Define this to have only one frame in the XMIT or RECV queue */ /* Toshiba's drivers do this, but it disables back to back tansfers */ /* I think that the chip may have some problems certainly, I have */ @@ -682,7 +651,7 @@ toshoboe_close (struct toshoboe_cb *self) toshoboe_disablebm (self); } - release_region (self->io.iobase, self->io.io_ext); + release_region (self->io.sir_base, self->io.sir_ext); for (i = 0; i < TX_SLOTS; ++i) @@ -754,17 +723,17 @@ toshoboe_open (struct pci_dev *pci_dev) self->pdev = pci_dev; self->base = pci_dev->resource[0].start; - self->io.iobase = self->base; + self->io.sir_base = self->base; self->io.irq = pci_dev->irq; - self->io.io_ext = CHIP_IO_EXTENT; + self->io.sir_ext = CHIP_IO_EXTENT; self->io.speed = 9600; /* Lock the port that we need */ - i = check_region (self->io.iobase, self->io.io_ext); + i = check_region (self->io.sir_base, self->io.sir_ext); if (i < 0) { IRDA_DEBUG (0, __FUNCTION__ "(), can't get iobase of 0x%03x\n", - self->io.iobase); + self->io.sir_base); dev_self[i] = NULL; kfree (self); @@ -864,13 +833,12 @@ toshoboe_open (struct pci_dev *pci_dev) } - request_region (self->io.iobase, self->io.io_ext, driver_name); + request_region (self->io.sir_base, self->io.sir_ext, driver_name); if (!(dev = dev_alloc("irda%d", &err))) { ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); return -ENOMEM; } - dev->priv = (void *) self; self->netdev = dev; @@ -1025,7 +993,7 @@ int __init toshoboe_init (void) if (pci_dev) { printk (KERN_WARNING "ToshOboe: Found 701 chip at 0x%0lx irq %d\n", - pci_dev->resource[0].start, + pci_dev->resource[0].start, pci_dev->irq); if (!toshoboe_open (pci_dev)) diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c index 1bc2d9fa9..7f781719c 100644 --- a/drivers/net/irda/w83977af_ir.c +++ b/drivers/net/irda/w83977af_ir.c @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Paul VanderSpek * Created at: Wed Nov 4 11:46:16 1998 - * Modified at: Wed Jan 5 15:11:21 2000 + * Modified at: Fri Jan 28 12:10:59 2000 * Modified by: Dag Brattli <dagb@cs.uit.no> * * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no> @@ -183,21 +183,21 @@ int w83977af_open(int i, unsigned int iobase, unsigned int irq, dev_self[i] = self; /* Initialize IO */ - self->io.iobase = iobase; + self->io.fir_base = iobase; self->io.irq = irq; - self->io.io_ext = CHIP_IO_EXTENT; + self->io.fir_ext = CHIP_IO_EXTENT; self->io.dma = dma; self->io.fifo_size = 32; /* Lock the port that we need */ - ret = check_region(self->io.iobase, self->io.io_ext); + ret = check_region(self->io.fir_base, self->io.fir_ext); if (ret < 0) { IRDA_DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n", - self->io.iobase); + self->io.fir_base); /* w83977af_cleanup( self); */ return -ENODEV; } - request_region(self->io.iobase, self->io.io_ext, driver_name); + request_region(self->io.fir_base, self->io.fir_ext, driver_name); /* Initialize QoS for this device */ irda_init_max_qos_capabilies(&self->qos); @@ -243,9 +243,6 @@ int w83977af_open(int i, unsigned int iobase, unsigned int irq, ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); return -ENOMEM; } - /* dev_alloc doesn't clear the struct, so lets do a little hack */ - memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct net_device)-sizeof(char*)); - dev->priv = (void *) self; self->netdev = dev; @@ -282,7 +279,7 @@ static int w83977af_close(struct w83977af_ir *self) IRDA_DEBUG(0, __FUNCTION__ "()\n"); - iobase = self->io.iobase; + iobase = self->io.fir_base; #ifdef CONFIG_USE_W977_PNP /* enter PnP configuration mode */ @@ -301,14 +298,12 @@ static int w83977af_close(struct w83977af_ir *self) rtnl_lock(); unregister_netdevice(self->netdev); rtnl_unlock(); - /* Must free the old-style 2.2.x device */ - kfree(self->netdev); } /* Release the PORT that this driver is using */ IRDA_DEBUG(0 , __FUNCTION__ "(), Releasing Region %03x\n", - self->io.iobase); - release_region(self->io.iobase, self->io.io_ext); + self->io.fir_base); + release_region(self->io.fir_base, self->io.fir_ext); if (self->tx_buff.head) kfree(self->tx_buff.head); @@ -426,7 +421,7 @@ void w83977af_change_speed(struct w83977af_ir *self, __u32 speed) int iobase; __u8 set; - iobase = self->io.iobase; + iobase = self->io.fir_base; /* Update accounting for new speed */ self->io.speed = speed; @@ -510,7 +505,7 @@ int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev) self = (struct w83977af_ir *) dev->priv; - iobase = self->io.iobase; + iobase = self->io.fir_base; IRDA_DEBUG(4, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies, (int) skb->len); @@ -692,7 +687,7 @@ void w83977af_dma_xmit_complete(struct w83977af_ir *self) ASSERT(self != NULL, return;); - iobase = self->io.iobase; + iobase = self->io.fir_base; /* Save current set */ set = inb(iobase+SSR); @@ -748,7 +743,7 @@ int w83977af_dma_receive(struct w83977af_ir *self) IRDA_DEBUG(4, __FUNCTION__ "\n"); - iobase= self->io.iobase; + iobase= self->io.fir_base; /* Save current set */ set = inb(iobase+SSR); @@ -822,12 +817,12 @@ int w83977af_dma_receive_complete(struct w83977af_ir *self) st_fifo = &self->st_fifo; - iobase = self->io.iobase; + iobase = self->io.fir_base; /* Save current set */ set = inb(iobase+SSR); - iobase = self->io.iobase; + iobase = self->io.fir_base; /* Read status FIFO */ switch_bank(iobase, SET5); @@ -948,7 +943,7 @@ static void w83977af_pio_receive(struct w83977af_ir *self) ASSERT(self != NULL, return;); - iobase = self->io.iobase; + iobase = self->io.fir_base; /* Receive all characters in Rx FIFO */ do { @@ -973,11 +968,11 @@ static __u8 w83977af_sir_interrupt(struct w83977af_ir *self, int isr) IRDA_DEBUG(4, __FUNCTION__ "(), isr=%#x\n", isr); - iobase = self->io.iobase; + iobase = self->io.fir_base; /* Transmit FIFO low on data */ if (isr & ISR_TXTH_I) { /* Write data left in transmit buffer */ - actual = w83977af_pio_write(self->io.iobase, + actual = w83977af_pio_write(self->io.fir_base, self->tx_buff.data, self->tx_buff.len, self->io.fifo_size); @@ -1042,7 +1037,7 @@ static __u8 w83977af_fir_interrupt(struct w83977af_ir *self, int isr) __u8 set; int iobase; - iobase = self->io.iobase; + iobase = self->io.fir_base; set = inb(iobase+SSR); /* End of frame detected in FIFO */ @@ -1131,7 +1126,7 @@ static void w83977af_interrupt(int irq, void *dev_id, struct pt_regs *regs) dev->interrupt = 1; - iobase = self->io.iobase; + iobase = self->io.fir_base; /* Save current bank */ set = inb(iobase+SSR); @@ -1171,7 +1166,7 @@ static int w83977af_is_receiving(struct w83977af_ir *self) ASSERT(self != NULL, return FALSE;); if (self->io.speed > 115200) { - iobase = self->io.iobase; + iobase = self->io.fir_base; /* Check if rx FIFO is not empty */ set = inb(iobase+SSR); @@ -1225,7 +1220,7 @@ static int w83977af_net_open(struct net_device *dev) ASSERT(self != NULL, return 0;); - iobase = self->io.iobase; + iobase = self->io.fir_base; if (request_irq(self->io.irq, w83977af_interrupt, 0, dev->name, (void *) dev)) { @@ -1290,7 +1285,7 @@ static int w83977af_net_close(struct net_device *dev) ASSERT(self != NULL, return 0;); - iobase = self->io.iobase; + iobase = self->io.fir_base; /* Stop device */ dev->tbusy = 1; diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c new file mode 100644 index 000000000..ce43ad752 --- /dev/null +++ b/drivers/net/mac89x0.c @@ -0,0 +1,678 @@ +/* cs89x0.c: A Crystal Semiconductor CS89[02]0 driver for linux. */ +/* + Written 1996 by Russell Nelson, with reference to skeleton.c + written 1993-1994 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + The author may be reached at nelson@crynwr.com, Crynwr + Software, 11 Grant St., Potsdam, NY 13676 + + Changelog: + + Mike Cruse : mcruse@cti-ltd.com + : Changes for Linux 2.0 compatibility. + : Added dev_id parameter in net_interrupt(), + : request_irq() and free_irq(). Just NULL for now. + + Mike Cruse : Added MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT macros + : in net_open() and net_close() so kerneld would know + : that the module is in use and wouldn't eject the + : driver prematurely. + + Mike Cruse : Rewrote init_module() and cleanup_module using 8390.c + : as an example. Disabled autoprobing in init_module(), + : not a good thing to do to other devices while Linux + : is running from all accounts. + + Alan Cox : Removed 1.2 support, added 2.1 extra counters. + + David Huggins-Daines <dhd@debian.org> + + Split this off into mac89x0.c, and gutted it of all parts which are + not relevant to the existing CS8900 cards on the Macintosh + (i.e. basically the Daynaport CS and LC cards). To be precise: + + * Removed all the media-detection stuff, because these cards are + TP-only. + + * Lobotomized the ISA interrupt bogosity, because these cards use + a hardwired NuBus interrupt and a magic ISAIRQ value in the card. + + * Basically eliminated everything not relevant to getting the + cards minimally functioning on the Macintosh. + + I might add that these cards are badly designed even from the Mac + standpoint, in that Dayna, in their infinite wisdom, used NuBus slot + I/O space and NuBus interrupts for these cards, but neglected to + provide anything even remotely resembling a NuBus ROM. Therefore we + have to probe for them in a brain-damaged ISA-like fashion. +*/ + +static char *version = +"cs89x0.c:v1.02 11/26/96 Russell Nelson <nelson@crynwr.com>\n"; + +/* ======================= configure the driver here ======================= */ + +/* use 0 for production, 1 for verification, >2 for debug */ +#ifndef NET_DEBUG +#define NET_DEBUG 0 +#endif + +/* ======================= end of configuration ======================= */ + + +/* Always include 'config.h' first in case the user wants to turn on + or override something. */ +#ifdef MODULE +#include <linux/module.h> +#include <linux/version.h> +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + +#define PRINTK(x) printk x + +/* + Sources: + + Crynwr packet driver epktisa. + + Crystal Semiconductor data sheets. + +*/ + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/fcntl.h> +#include <linux/interrupt.h> +#include <linux/ptrace.h> +#include <linux/ioport.h> +#include <linux/in.h> +#include <linux/malloc.h> +#include <linux/string.h> +#include <linux/nubus.h> +#include <asm/system.h> +#include <asm/bitops.h> +#include <asm/io.h> +#include <asm/hwtest.h> +#include <asm/macints.h> +#include <linux/errno.h> +#include <linux/init.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include "cs89x0.h" + +static unsigned int net_debug = NET_DEBUG; + +/* Information that need to be kept for each board. */ +struct net_local { + struct net_device_stats stats; + int chip_type; /* one of: CS8900, CS8920, CS8920M */ + char chip_revision; /* revision letter of the chip ('A'...) */ + int send_cmd; /* the propercommand used to send a packet. */ + int rx_mode; + int curr_rx_cfg; + int send_underrun; /* keep track of how many underruns in a row we get */ + struct sk_buff *skb; +}; + +/* Index to functions, as function prototypes. */ + +extern int mac89x0_probe(struct net_device *dev); +extern void reset_chip(struct net_device *dev); +static int net_open(struct net_device *dev); +static int net_send_packet(struct sk_buff *skb, struct net_device *dev); +static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void set_multicast_list(struct net_device *dev); +static void net_rx(struct net_device *dev); +static int net_close(struct net_device *dev); +static struct net_device_stats *net_get_stats(struct net_device *dev); +static int set_mac_address(struct net_device *dev, void *addr); + + +/* Example routines you must write ;->. */ +#define tx_done(dev) 1 + +/* For reading/writing registers ISA-style */ +static int inline +readreg_io(struct net_device *dev, int portno) +{ + writew(swab16(portno), dev->base_addr + ADD_PORT); + return swab16(readw(dev->base_addr + DATA_PORT)); +} + +static void inline +writereg_io(struct net_device *dev, int portno, int value) +{ + writew(swab16(portno), dev->base_addr + ADD_PORT); + writew(swab16(value), dev->base_addr + DATA_PORT); +} + +/* These are for reading/writing registers in shared memory */ +static int inline +readreg(struct net_device *dev, int portno) +{ + return swab16(readw(dev->mem_start + portno)); +} + +static void inline +writereg(struct net_device *dev, int portno, int value) +{ + writew(swab16(value), dev->mem_start + portno); +} + +/* Probe for the CS8900 card in slot E. We won't bother looking + anywhere else until we have a really good reason to do so. */ +int __init mac89x0_probe(struct net_device *dev) +{ + static int once_is_enough = 0; + struct net_local *lp; + static unsigned version_printed = 0; + int i, slot; + unsigned rev_type = 0; + unsigned long ioaddr; + unsigned short sig; + + if (once_is_enough) + return ENODEV; + once_is_enough = 1; + + /* We might have to parameterize this later */ + slot = 0xE; + /* Get out now if there's a real NuBus card in slot E */ + if (nubus_find_slot(slot, NULL) != NULL) + return ENODEV; + + /* The pseudo-ISA bits always live at offset 0x300 (gee, + wonder why...) */ + ioaddr = (unsigned long) + nubus_slot_addr(slot) | (((slot&0xf) << 20) + DEFAULTIOBASE); + { + unsigned long flags; + int card_present; + + save_flags(flags); + cli(); + card_present = hwreg_present((void*) ioaddr+4) + && hwreg_present((void*) ioaddr + DATA_PORT); + restore_flags(flags); + + if (!card_present) + return ENODEV; + } + + writew(0, ioaddr + ADD_PORT); + sig = readw(ioaddr + DATA_PORT); + if (sig != swab16(CHIP_EISA_ID_SIG)) + return ENODEV; + + /* Initialize the net_device structure. */ + if (dev->priv == NULL) { + dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); + memset(dev->priv, 0, sizeof(struct net_local)); + } + lp = (struct net_local *)dev->priv; + + /* Fill in the 'dev' fields. */ + dev->base_addr = ioaddr; + dev->mem_start = (unsigned long) + nubus_slot_addr(slot) | (((slot&0xf) << 20) + MMIOBASE); + dev->mem_end = dev->mem_start + 0x1000; + + /* Turn on shared memory */ + writereg_io(dev, PP_BusCTL, MEMORY_ON); + + /* get the chip type */ + rev_type = readreg(dev, PRODUCT_ID_ADD); + lp->chip_type = rev_type &~ REVISON_BITS; + lp->chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A'; + + /* Check the chip type and revision in order to set the correct send command + CS8920 revision C and CS8900 revision F can use the faster send. */ + lp->send_cmd = TX_AFTER_381; + if (lp->chip_type == CS8900 && lp->chip_revision >= 'F') + lp->send_cmd = TX_NOW; + if (lp->chip_type != CS8900 && lp->chip_revision >= 'C') + lp->send_cmd = TX_NOW; + + if (net_debug && version_printed++ == 0) + printk(version); + + printk(KERN_INFO "%s: cs89%c0%s rev %c found at %#8lx", + dev->name, + lp->chip_type==CS8900?'0':'2', + lp->chip_type==CS8920M?"M":"", + lp->chip_revision, + dev->base_addr); + + /* Try to read the MAC address */ + if ((readreg(dev, PP_SelfST) & (EEPROM_PRESENT | EEPROM_OK)) == 0) { + printk("\nmac89x0: No EEPROM, giving up now.\n"); + return ENODEV; + } else { + for (i = 0; i < ETH_ALEN; i += 2) { + /* Big-endian (why??!) */ + unsigned short s = readreg(dev, PP_IA + i); + dev->dev_addr[i] = s >> 8; + dev->dev_addr[i+1] = s & 0xff; + } + } + + dev->irq = SLOT2IRQ(slot); + printk(" IRQ %d ADDR ", dev->irq); + + /* print the ethernet address. */ + for (i = 0; i < ETH_ALEN; i++) + printk("%2.2x%s", dev->dev_addr[i], + ((i < ETH_ALEN-1) ? ":" : "")); + + dev->open = net_open; + dev->stop = net_close; + dev->hard_start_xmit = net_send_packet; + dev->get_stats = net_get_stats; + dev->set_multicast_list = &set_multicast_list; + dev->set_mac_address = &set_mac_address; + + /* Fill in the fields of the net_device structure with ethernet values. */ + ether_setup(dev); + + printk("\n"); + return 0; +} + +/* This is useful for something, but I don't know what yet. */ +void __init reset_chip(struct net_device *dev) +{ + int reset_start_time; + + writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET); + + /* wait 30 ms */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(30*HZ/1000); + + /* Wait until the chip is reset */ + reset_start_time = jiffies; + while( (readreg(dev, PP_SelfST) & INIT_DONE) == 0 && jiffies - reset_start_time < 2) + ; +} + +/* Open/initialize the board. This is called (in the current kernel) + sometime after booting when the 'ifconfig' program is run. + + This routine should set everything up anew at each open, even + registers that "should" only need to be set once at boot, so that + there is non-reboot way to recover if something goes wrong. + */ +static int +net_open(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + int i; + + /* Disable the interrupt for now */ + writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) & ~ENABLE_IRQ); + + /* Grab the interrupt */ + if (request_irq(dev->irq, &net_interrupt, 0, "cs89x0", dev)) + return -EAGAIN; + + /* Set up the IRQ - Apparently magic */ + if (lp->chip_type == CS8900) + writereg(dev, PP_CS8900_ISAINT, 0); + else + writereg(dev, PP_CS8920_ISAINT, 0); + + /* set the Ethernet address */ + for (i=0; i < ETH_ALEN/2; i++) + writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8)); + + /* Turn on both receive and transmit operations */ + writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON); + + /* Receive only error free packets addressed to this card */ + lp->rx_mode = 0; + writereg(dev, PP_RxCTL, DEF_RX_ACCEPT); + + lp->curr_rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL; + + writereg(dev, PP_RxCFG, lp->curr_rx_cfg); + + writereg(dev, PP_TxCFG, TX_LOST_CRS_ENBL | TX_SQE_ERROR_ENBL | TX_OK_ENBL | + TX_LATE_COL_ENBL | TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL); + + writereg(dev, PP_BufCFG, READY_FOR_TX_ENBL | RX_MISS_COUNT_OVRFLOW_ENBL | + TX_COL_COUNT_OVRFLOW_ENBL | TX_UNDERRUN_ENBL); + + /* now that we've got our act together, enable everything */ + writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) | ENABLE_IRQ); + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + MOD_INC_USE_COUNT; + return 0; +} + +static int +net_send_packet(struct sk_buff *skb, struct net_device *dev) +{ + if (dev->tbusy) { + /* If we get here, some higher level has decided we are broken. + There should really be a "kick me" function call instead. */ + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 5) + return 1; + if (net_debug > 0) printk("%s: transmit timed out, %s?\n", dev->name, + tx_done(dev) ? "IRQ conflict" : "network cable problem"); + /* Try to restart the adaptor. */ + dev->tbusy=0; + dev->trans_start = jiffies; + } + + /* Block a timer-based transmit from overlapping. This could better be + done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) + printk("%s: Transmitter access conflict.\n", dev->name); + else { + struct net_local *lp = (struct net_local *)dev->priv; + unsigned long flags; + + if (net_debug > 3) + printk("%s: sent %d byte packet of type %x\n", + dev->name, skb->len, + (skb->data[ETH_ALEN+ETH_ALEN] << 8) + | skb->data[ETH_ALEN+ETH_ALEN+1]); + + /* keep the upload from being interrupted, since we + ask the chip to start transmitting before the + whole packet has been completely uploaded. */ + save_flags(flags); + cli(); + + /* initiate a transmit sequence */ + writereg(dev, PP_TxCMD, lp->send_cmd); + writereg(dev, PP_TxLength, skb->len); + + /* Test to see if the chip has allocated memory for the packet */ + if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) { + /* Gasp! It hasn't. But that shouldn't happen since + we're waiting for TxOk, so return 1 and requeue this packet. */ + restore_flags(flags); + return 1; + } + + /* Write the contents of the packet */ + memcpy_toio(dev->mem_start + PP_TxFrame, skb->data, skb->len+1); + + restore_flags(flags); + dev->trans_start = jiffies; + } + dev_kfree_skb (skb); + + return 0; +} + +/* The typical workload of the driver: + Handle the network interface interrupts. */ +static void net_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct net_device *dev = dev_id; + struct net_local *lp; + int ioaddr, status; + + if (dev == NULL) { + printk ("net_interrupt(): irq %d for unknown device.\n", irq); + return; + } + if (dev->interrupt) + printk("%s: Re-entering the interrupt handler.\n", dev->name); + dev->interrupt = 1; + + ioaddr = dev->base_addr; + lp = (struct net_local *)dev->priv; + + /* we MUST read all the events out of the ISQ, otherwise we'll never + get interrupted again. As a consequence, we can't have any limit + on the number of times we loop in the interrupt handler. The + hardware guarantees that eventually we'll run out of events. Of + course, if you're on a slow machine, and packets are arriving + faster than you can read them off, you're screwed. Hasta la + vista, baby! */ + while ((status = swab16(readw(dev->base_addr + ISQ_PORT)))) { + if (net_debug > 4)printk("%s: event=%04x\n", dev->name, status); + switch(status & ISQ_EVENT_MASK) { + case ISQ_RECEIVER_EVENT: + /* Got a packet(s). */ + net_rx(dev); + break; + case ISQ_TRANSMITTER_EVENT: + lp->stats.tx_packets++; + dev->tbusy = 0; + mark_bh(NET_BH); /* Inform upper layers. */ + if ((status & TX_OK) == 0) lp->stats.tx_errors++; + if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++; + if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++; + if (status & TX_LATE_COL) lp->stats.tx_window_errors++; + if (status & TX_16_COL) lp->stats.tx_aborted_errors++; + break; + case ISQ_BUFFER_EVENT: + if (status & READY_FOR_TX) { + /* we tried to transmit a packet earlier, + but inexplicably ran out of buffers. + That shouldn't happen since we only ever + load one packet. Shrug. Do the right + thing anyway. */ + dev->tbusy = 0; + mark_bh(NET_BH); /* Inform upper layers. */ + } + if (status & TX_UNDERRUN) { + if (net_debug > 0) printk("%s: transmit underrun\n", dev->name); + lp->send_underrun++; + if (lp->send_underrun == 3) lp->send_cmd = TX_AFTER_381; + else if (lp->send_underrun == 6) lp->send_cmd = TX_AFTER_ALL; + } + break; + case ISQ_RX_MISS_EVENT: + lp->stats.rx_missed_errors += (status >>6); + break; + case ISQ_TX_COL_EVENT: + lp->stats.collisions += (status >>6); + break; + } + } + dev->interrupt = 0; + return; +} + +/* We have a good packet(s), get it/them out of the buffers. */ +static void +net_rx(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + struct sk_buff *skb; + int status, length; + + status = readreg(dev, PP_RxStatus); + if ((status & RX_OK) == 0) { + lp->stats.rx_errors++; + if (status & RX_RUNT) lp->stats.rx_length_errors++; + if (status & RX_EXTRA_DATA) lp->stats.rx_length_errors++; + if (status & RX_CRC_ERROR) if (!(status & (RX_EXTRA_DATA|RX_RUNT))) + /* per str 172 */ + lp->stats.rx_crc_errors++; + if (status & RX_DRIBBLE) lp->stats.rx_frame_errors++; + return; + } + + length = readreg(dev, PP_RxLength); + /* Malloc up new buffer. */ + skb = alloc_skb(length, GFP_ATOMIC); + if (skb == NULL) { + printk("%s: Memory squeeze, dropping packet.\n", dev->name); + lp->stats.rx_dropped++; + return; + } + skb->len = length; + skb->dev = dev; + + memcpy_fromio(skb->data, dev->mem_start + PP_RxFrame, length); + + if (net_debug > 3)printk("%s: received %d byte packet of type %x\n", + dev->name, length, + (skb->data[ETH_ALEN+ETH_ALEN] << 8) + | skb->data[ETH_ALEN+ETH_ALEN+1]); + + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); + lp->stats.rx_packets++; + lp->stats.rx_bytes+=skb->len; + return; +} + +/* The inverse routine to net_open(). */ +static int +net_close(struct net_device *dev) +{ + + writereg(dev, PP_RxCFG, 0); + writereg(dev, PP_TxCFG, 0); + writereg(dev, PP_BufCFG, 0); + writereg(dev, PP_BusCTL, 0); + + dev->start = 0; + + free_irq(dev->irq, dev); + + /* Update the statistics here. */ + + MOD_DEC_USE_COUNT; + return 0; + +} + +/* Get the current statistics. This may be called with the card open or + closed. */ +static struct net_device_stats * +net_get_stats(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + cli(); + /* Update the statistics from the device registers. */ + lp->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6); + lp->stats.collisions += (readreg(dev, PP_TxCol) >> 6); + sti(); + + return &lp->stats; +} + +static void set_multicast_list(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + if(dev->flags&IFF_PROMISC) + { + lp->rx_mode = RX_ALL_ACCEPT; + } + else if((dev->flags&IFF_ALLMULTI)||dev->mc_list) + { + /* The multicast-accept list is initialized to accept-all, and we + rely on higher-level filtering for now. */ + lp->rx_mode = RX_MULTCAST_ACCEPT; + } + else + lp->rx_mode = 0; + + writereg(dev, PP_RxCTL, DEF_RX_ACCEPT | lp->rx_mode); + + /* in promiscuous mode, we accept errored packets, so we have to enable interrupts on them also */ + writereg(dev, PP_RxCFG, lp->curr_rx_cfg | + (lp->rx_mode == RX_ALL_ACCEPT? (RX_CRC_ERROR_ENBL|RX_RUNT_ENBL|RX_EXTRA_DATA_ENBL) : 0)); +} + + +static int set_mac_address(struct net_device *dev, void *addr) +{ + int i; + if (dev->start) + return -EBUSY; + printk("%s: Setting MAC address to ", dev->name); + for (i = 0; i < 6; i++) + printk(" %2.2x", dev->dev_addr[i] = ((unsigned char *)addr)[i]); + printk(".\n"); + /* set the Ethernet address */ + for (i=0; i < ETH_ALEN/2; i++) + writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8)); + + return 0; +} + +#ifdef MODULE + +static char namespace[16] = ""; +static struct net_device dev_cs89x0 = { + NULL, + 0, 0, 0, 0, + 0, 0, + 0, 0, 0, NULL, NULL }; + +static int debug=0; + +MODULE_PARM(debug, "i"); + +EXPORT_NO_SYMBOLS; + +int +init_module(void) +{ + struct net_local *lp; + + net_debug = debug; + dev_cs89x0.name = namespace; + dev_cs89x0.init = mac89x0_probe; + dev_cs89x0.priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); + memset(dev_cs89x0.priv, 0, sizeof(struct net_local)); + lp = (struct net_local *)dev_cs89x0.priv; + + if (register_netdev(&dev_cs89x0) != 0) { + printk(KERN_WARNING "mac89x0.c: No card found\n"); + return -ENXIO; + } + return 0; +} + +void +cleanup_module(void) +{ + +#endif +#ifdef MODULE + writew(0, dev_cs89x0.base_addr + ADD_PORT); +#endif +#ifdef MODULE + + if (dev_cs89x0.priv != NULL) { + /* Free up the private structure, or leak memory :-) */ + unregister_netdev(&dev_cs89x0); + kfree(dev_cs89x0.priv); + dev_cs89x0.priv = NULL; /* gets re-allocated by cs89x0_probe1 */ + } +} +#endif /* MODULE */ + +/* + * Local variables: + * compile-command: "m68k-linux-gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -ffixed-a2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c -o mac89x0.o mac89x0.c" + * version-control: t + * kept-new-versions: 5 + * c-indent-level: 8 + * tab-width: 8 + * End: + * + */ diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c new file mode 100644 index 000000000..a7c347a7d --- /dev/null +++ b/drivers/net/macmace.c @@ -0,0 +1,825 @@ +/* + * Driver for the Macintosh 68K onboard MACE controller with PSC + * driven DMA. The MACE driver code is derived from mace.c. The + * Mac68k theory of operation is courtesy of the MacBSD wizards. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Copyright (C) 1996 Paul Mackerras. + * Copyright (C) 1998 Alan Cox <alan@redhat.com> + */ + + +#include <linux/kernel.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/delay.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/irq.h> +#include <asm/macintosh.h> +#include <asm/macints.h> +#include <asm/mac_psc.h> +#include "mace.h" + +#define N_RX_RING 8 +#define N_TX_RING 2 +#define MAX_TX_ACTIVE 1 +#define NCMDS_TX 1 /* dma commands per element in tx ring */ +#define RX_BUFLEN (ETH_FRAME_LEN + 8) +#define TX_TIMEOUT HZ /* 1 second */ + +/* Bits in transmit DMA status */ +#define TX_DMA_ERR 0x80 + +/* The MACE is simply wired down on a Mac68K box */ + +#define MACE_BASE (void *)(0x50F1C000) +#define MACE_PROM (void *)(0x50F08001) + +struct mace68k_data +{ + volatile struct mace *mace; + volatile unsigned char *tx_ring; + volatile unsigned char *rx_ring; + int dma_intr; + unsigned char maccc; + struct net_device_stats stats; + struct timer_list tx_timeout; + int timeout_active; + int rx_slot, rx_done; + int tx_slot, tx_count; +}; + +struct mace_frame +{ + u16 len; + u16 status; + u16 rntpc; + u16 rcvcc; + u32 pad1; + u32 pad2; + u8 data[1]; + /* And frame continues.. */ +}; + +#define PRIV_BYTES sizeof(struct mace68k_data) + +extern void psc_debug_dump(void); + +static int mace68k_open(struct net_device *dev); +static int mace68k_close(struct net_device *dev); +static int mace68k_xmit_start(struct sk_buff *skb, struct net_device *dev); +static struct net_device_stats *mace68k_stats(struct net_device *dev); +static void mace68k_set_multicast(struct net_device *dev); +static void mace68k_reset(struct net_device *dev); +static int mace68k_set_address(struct net_device *dev, void *addr); +static void mace68k_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void mace68k_dma_intr(int irq, void *dev_id, struct pt_regs *regs); +static void mace68k_set_timeout(struct net_device *dev); +static void mace68k_tx_timeout(unsigned long data); + +/* + * PSC DMA engine control. As you'd expect on a macintosh its + * more like a lawnmower engine supplied without instructions + * + * The basic theory of operation appears to be as follows. + * + * There are two sets of receive DMA registers and two sets + * of transmit DMA registers. Instead of the more traditional + * "ring buffer" approach the Mac68K DMA engine expects you + * to be loading one chain while the other runs, and then + * to flip register set. Each entry in the chain is a fixed + * length. + */ + +/* + * Load a receive DMA channel with a base address and ring length + */ + +static void psc_load_rxdma_base(int set, void *base) +{ + psc_write_word(PSC_ENETRD_CMD + set, 0x0100); + psc_write_long(PSC_ENETRD_ADDR + set, (u32)base); + psc_write_long(PSC_ENETRD_LEN + set, N_RX_RING); + psc_write_word(PSC_ENETRD_CMD + set, 0x9800); +} + +/* + * Reset the receive DMA subsystem + */ + +static void mace68k_rxdma_reset(struct net_device *dev) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + volatile struct mace *mace = mp->mace; + u8 mcc = mace->maccc; + + /* + * Turn off receive + */ + + mcc&=~ENRCV; + mace->maccc=mcc; + + /* + * Program the DMA + */ + + psc_write_word(PSC_ENETRD_CTL, 0x8800); + psc_load_rxdma_base(0x0, (void *)virt_to_bus(mp->rx_ring)); + psc_write_word(PSC_ENETRD_CTL, 0x0400); + + psc_write_word(PSC_ENETRD_CTL, 0x8800); + psc_load_rxdma_base(0x10, (void *)virt_to_bus(mp->rx_ring)); + psc_write_word(PSC_ENETRD_CTL, 0x0400); + + mace->maccc=mcc|ENRCV; + +#if 0 + psc_write_word(PSC_ENETRD_CTL, 0x9800); + psc_write_word(PSC_ENETRD_CTL+0x10, 0x9800); +#endif +} + +/* + * Reset the transmit DMA subsystem + */ + +static void mace68k_txdma_reset(struct net_device *dev) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + volatile struct mace *mace = mp->mace; + u8 mcc = mace->maccc; + + psc_write_word(PSC_ENETWR_CTL,0x8800); + + mace->maccc = mcc&~ENXMT; + psc_write_word(PSC_ENETWR_CTL,0x0400); + mace->maccc = mcc; +} + +/* + * Disable DMA + */ + +static void mace68k_dma_off(struct net_device *dev) +{ + psc_write_word(PSC_ENETRD_CTL, 0x8800); + psc_write_word(PSC_ENETRD_CTL, 0x1000); + psc_write_word(PSC_ENETRD_CMD, 0x1100); + psc_write_word(PSC_ENETRD_CMD+0x10, 0x1100); + + psc_write_word(PSC_ENETWR_CTL, 0x8800); + psc_write_word(PSC_ENETWR_CTL, 0x1000); + psc_write_word(PSC_ENETWR_CMD, 0x1100); + psc_write_word(PSC_ENETWR_CMD+0x10, 0x1100); +} + +/* Bit-reverse one byte of an ethernet hardware address. */ + +static int bitrev(int b) +{ + int d = 0, i; + + for (i = 0; i < 8; ++i, b >>= 1) + d = (d << 1) | (b & 1); + return d; +} + +/* + * Not really much of a probe. The hardware table tells us if this + * model of Macintrash has a MACE (AV macintoshes) + */ + +int mace68k_probe(struct net_device *unused) +{ + int j; + static int once=0; + struct mace68k_data *mp; + unsigned char *addr; + struct net_device *dev; + unsigned char checksum = 0; + + /* + * There can be only one... + */ + + if (once) return -ENODEV; + + once = 1; + + if (macintosh_config->ether_type != MAC_ETHER_MACE) return -ENODEV; + + printk("MACE ethernet should be present "); + + dev = init_etherdev(0, PRIV_BYTES); + if(dev==NULL) + { + printk("no free memory.\n"); + return -ENOMEM; + } + mp = (struct mace68k_data *) dev->priv; + dev->base_addr = (u32)MACE_BASE; + mp->mace = (volatile struct mace *) MACE_BASE; + + printk("at 0x%p", mp->mace); + + /* + * 16K RX ring and 4K TX ring should do nicely + */ + + mp->rx_ring=(void *)__get_free_pages(GFP_KERNEL, 2); + mp->tx_ring=(void *)__get_free_page(GFP_KERNEL); + + printk("."); + + if(mp->tx_ring==NULL || mp->rx_ring==NULL) + { + if(mp->tx_ring) + free_page((u32)mp->tx_ring); +// if(mp->rx_ring) +// __free_pages(mp->rx_ring,2); + printk("\nNo memory for ring buffers.\n"); + return -ENOMEM; + } + + /* We want the receive data to be uncached. We dont care about the + byte reading order */ + + printk("."); + kernel_set_cachemode((void *)mp->rx_ring, 16384, IOMAP_NOCACHE_NONSER); + + printk("."); + /* The transmit buffer needs to be write through */ + kernel_set_cachemode((void *)mp->tx_ring, 4096, IOMAP_WRITETHROUGH); + + printk(" Ok\n"); + dev->irq = IRQ_MAC_MACE; + printk(KERN_INFO "%s: MACE at", dev->name); + + /* + * The PROM contains 8 bytes which total 0xFF when XOR'd + * together. Due to the usual peculiar apple brain damage + * the bytes are spaced out in a strange boundary and the + * bits are reversed. + */ + + addr = (void *)MACE_PROM; + + for (j = 0; j < 6; ++j) + { + u8 v=bitrev(addr[j<<4]); + checksum^=v; + dev->dev_addr[j] = v; + printk("%c%.2x", (j ? ':' : ' '), dev->dev_addr[j]); + } + for (; j < 8; ++j) + { + checksum^=bitrev(addr[j<<4]); + } + + if(checksum!=0xFF) + { + printk(" (invalid checksum)\n"); + return -ENODEV; + } + printk("\n"); + + memset(&mp->stats, 0, sizeof(mp->stats)); + init_timer(&mp->tx_timeout); + mp->timeout_active = 0; + + dev->open = mace68k_open; + dev->stop = mace68k_close; + dev->hard_start_xmit = mace68k_xmit_start; + dev->get_stats = mace68k_stats; + dev->set_multicast_list = mace68k_set_multicast; + dev->set_mac_address = mace68k_set_address; + + ether_setup(dev); + + mp = (struct mace68k_data *) dev->priv; + mp->maccc = ENXMT | ENRCV; + mp->dma_intr = IRQ_MAC_MACE_DMA; + + psc_write_word(PSC_ENETWR_CTL, 0x9000); + psc_write_word(PSC_ENETRD_CTL, 0x9000); + psc_write_word(PSC_ENETWR_CTL, 0x0400); + psc_write_word(PSC_ENETRD_CTL, 0x0400); + + /* apple's driver doesn't seem to do this */ + /* except at driver shutdown time... */ +#if 0 + mace68k_dma_off(dev); +#endif + + return 0; +} + +/* + * Reset a MACE controller + */ + +static void mace68k_reset(struct net_device *dev) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + volatile struct mace *mb = mp->mace; + int i; + + /* soft-reset the chip */ + i = 200; + while (--i) { + mb->biucc = SWRST; + if (mb->biucc & SWRST) { + udelay(10); + continue; + } + break; + } + if (!i) { + printk(KERN_ERR "mace: cannot reset chip!\n"); + return; + } + + mb->biucc = XMTSP_64; + mb->imr = 0xff; /* disable all intrs for now */ + i = mb->ir; + mb->maccc = 0; /* turn off tx, rx */ + mb->utr = RTRD; + mb->fifocc = RCVFW_64; + mb->xmtfc = AUTO_PAD_XMIT; /* auto-pad short frames */ + + /* load up the hardware address */ + + mb->iac = ADDRCHG | PHYADDR; + + while ((mb->iac & ADDRCHG) != 0); + + for (i = 0; i < 6; ++i) + mb->padr = dev->dev_addr[i]; + + /* clear the multicast filter */ + mb->iac = ADDRCHG | LOGADDR; + + while ((mb->iac & ADDRCHG) != 0); + + for (i = 0; i < 8; ++i) + mb->ladrf = 0; + + mb->plscc = PORTSEL_GPSI + ENPLSIO; +} + +/* + * Load the address on a mace controller. + */ + +static int mace68k_set_address(struct net_device *dev, void *addr) +{ + unsigned char *p = addr; + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + volatile struct mace *mb = mp->mace; + int i; + unsigned long flags; + + save_flags(flags); + cli(); + + /* load up the hardware address */ + mb->iac = ADDRCHG | PHYADDR; + while ((mb->iac & ADDRCHG) != 0); + + for (i = 0; i < 6; ++i) + mb->padr = dev->dev_addr[i] = p[i]; + /* note: setting ADDRCHG clears ENRCV */ + mb->maccc = mp->maccc; + restore_flags(flags); + return 0; +} + +/* + * Open the Macintosh MACE. Most of this is playing with the DMA + * engine. The ethernet chip is quite friendly. + */ + +static int mace68k_open(struct net_device *dev) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + volatile struct mace *mb = mp->mace; + + /* reset the chip */ + mace68k_reset(dev); + + mp->rx_done = 0; + mace68k_rxdma_reset(dev); + + /* + * The interrupt is fixed and comes off the PSC. + */ + + if (request_irq(dev->irq, mace68k_interrupt, 0, "68K MACE", dev)) + { + printk(KERN_ERR "MACE: can't get irq %d\n", dev->irq); + return -EAGAIN; + } + + /* + * Ditto the DMA interrupt. + */ + + if (request_irq(IRQ_MAC_MACE_DMA, mace68k_dma_intr, 0, "68K MACE DMA", + dev)) + { + printk(KERN_ERR "MACE: can't get irq %d\n", IRQ_MAC_MACE_DMA); + return -EAGAIN; + } + + /* Activate the Mac DMA engine */ + + mp->tx_slot = 0; /* Using register set 0 */ + mp->tx_count = 1; /* 1 Buffer ready for use */ + mace68k_txdma_reset(dev); + + /* turn it on! */ + mb->maccc = mp->maccc; + /* enable all interrupts except receive interrupts */ + mb->imr = RCVINT; + return 0; +} + +/* + * Shut down the mace and its interrupt channel + */ + +static int mace68k_close(struct net_device *dev) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + volatile struct mace *mb = mp->mace; + + /* disable rx and tx */ + mb->maccc = 0; + mb->imr = 0xff; /* disable all intrs */ + + /* disable rx and tx dma */ + + mace68k_dma_off(dev); + + free_irq(dev->irq, dev); + free_irq(IRQ_MAC_MACE_DMA, dev); + return 0; +} + +static inline void mace68k_set_timeout(struct net_device *dev) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + unsigned long flags; + + save_flags(flags); + cli(); + if (mp->timeout_active) + del_timer(&mp->tx_timeout); + mp->tx_timeout.expires = jiffies + TX_TIMEOUT; + mp->tx_timeout.function = mace68k_tx_timeout; + mp->tx_timeout.data = (unsigned long) dev; + add_timer(&mp->tx_timeout); + mp->timeout_active = 1; + restore_flags(flags); +} + +/* + * Transmit a frame + */ + +static int mace68k_xmit_start(struct sk_buff *skb, struct net_device *dev) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + /* + * This may need atomic types ??? + */ + + printk("mace68k_xmit_start: mp->tx_count = %d, dev->tbusy = %d, mp->tx_ring = %p (%p)\n", + mp->tx_count, dev->tbusy, + mp->tx_ring, virt_to_bus(mp->tx_ring)); + psc_debug_dump(); + + if(mp->tx_count == 0) + { + dev->tbusy=1; + mace68k_dma_intr(IRQ_MAC_MACE_DMA, dev, NULL); + return 1; + } + mp->tx_count--; + + /* + * FIXME: + * This is hackish. The memcpy probably isnt needed but + * the rules for alignment are not known. Ideally we'd like + * to just blast the skb directly to ethernet. We also don't + * use the ring properly - just a one frame buffer. That + * also requires cache pushes ;). + */ + memcpy((void *)mp->tx_ring, skb, skb->len); + psc_write_long(PSC_ENETWR_ADDR + mp->tx_slot, virt_to_bus(mp->tx_ring)); + psc_write_long(PSC_ENETWR_LEN + mp->tx_slot, skb->len); + psc_write_word(PSC_ENETWR_CMD + mp->tx_slot, 0x9800); + mp->stats.tx_packets++; + mp->stats.tx_bytes+=skb->len; + dev_kfree_skb(skb); + return 0; +} + +static struct net_device_stats *mace68k_stats(struct net_device *dev) +{ + struct mace68k_data *p = (struct mace68k_data *) dev->priv; + return &p->stats; +} + +/* + * CRC polynomial - used in working out multicast filter bits. + */ +#define CRC_POLY 0xedb88320 + +static void mace68k_set_multicast(struct net_device *dev) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + volatile struct mace *mb = mp->mace; + int i, j, k, b; + unsigned long crc; + + mp->maccc &= ~PROM; + if (dev->flags & IFF_PROMISC) + { + mp->maccc |= PROM; + } else + { + unsigned char multicast_filter[8]; + struct dev_mc_list *dmi = dev->mc_list; + + if (dev->flags & IFF_ALLMULTI) + { + for (i = 0; i < 8; i++) + multicast_filter[i] = 0xff; + } else + { + for (i = 0; i < 8; i++) + multicast_filter[i] = 0; + for (i = 0; i < dev->mc_count; i++) + { + crc = ~0; + for (j = 0; j < 6; ++j) + { + b = dmi->dmi_addr[j]; + for (k = 0; k < 8; ++k) + { + if ((crc ^ b) & 1) + crc = (crc >> 1) ^ CRC_POLY; + else + crc >>= 1; + b >>= 1; + } + } + j = crc >> 26; /* bit number in multicast_filter */ + multicast_filter[j >> 3] |= 1 << (j & 7); + dmi = dmi->next; + } + } +#if 0 + printk("Multicast filter :"); + for (i = 0; i < 8; i++) + printk("%02x ", multicast_filter[i]); + printk("\n"); +#endif + + mb->iac = ADDRCHG | LOGADDR; + while ((mb->iac & ADDRCHG) != 0); + + for (i = 0; i < 8; ++i) + mb->ladrf = multicast_filter[i]; + } + /* reset maccc */ + mb->maccc = mp->maccc; +} + +/* + * Miscellaneous interrupts are handled here. We may end up + * having to bash the chip on the head for bad errors + */ + +static void mace68k_handle_misc_intrs(struct mace68k_data *mp, int intr) +{ + volatile struct mace *mb = mp->mace; + static int mace68k_babbles, mace68k_jabbers; + + if (intr & MPCO) + mp->stats.rx_missed_errors += 256; + mp->stats.rx_missed_errors += mb->mpc; /* reading clears it */ + if (intr & RNTPCO) + mp->stats.rx_length_errors += 256; + mp->stats.rx_length_errors += mb->rntpc; /* reading clears it */ + if (intr & CERR) + ++mp->stats.tx_heartbeat_errors; + if (intr & BABBLE) + if (mace68k_babbles++ < 4) + printk(KERN_DEBUG "mace: babbling transmitter\n"); + if (intr & JABBER) + if (mace68k_jabbers++ < 4) + printk(KERN_DEBUG "mace: jabbering transceiver\n"); +} + +/* + * A transmit error has occured. (We kick the transmit side from + * the DMA completion) + */ + +static void mace68k_xmit_error(struct net_device *dev) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + volatile struct mace *mb = mp->mace; + u8 xmtfs, xmtrc; + + xmtfs = mb->xmtfs; + xmtrc = mb->xmtrc; + + if(xmtfs & XMTSV) + { + if(xmtfs & UFLO) + { + printk("%s: DMA underrun.\n", dev->name); + mp->stats.tx_errors++; + mp->stats.tx_fifo_errors++; + mace68k_reset(dev); + } + if(xmtfs & RTRY) + mp->stats.collisions++; + } + mark_bh(NET_BH); +} + +/* + * A receive interrupt occured. + */ + +static void mace68k_recv_interrupt(struct net_device *dev) +{ +// struct mace68k_data *mp = (struct mace68k_data *) dev->priv; +// volatile struct mace *mb = mp->mace; +} + +/* + * Process the chip interrupt + */ + +static void mace68k_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + volatile struct mace *mb = mp->mace; + u8 ir; + + ir = mb->ir; + mace68k_handle_misc_intrs(mp, ir); + + if(ir&XMTINT) + mace68k_xmit_error(dev); + if(ir&RCVINT) + mace68k_recv_interrupt(dev); +} + +static void mace68k_tx_timeout(unsigned long data) +{ +// struct net_device *dev = (struct net_device *) data; +// struct mace68k_data *mp = (struct mace68k_data *) dev->priv; +// volatile struct mace *mb = mp->mace; +} + +/* + * Handle a newly arrived frame + */ + +static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + struct sk_buff *skb; + + if(mf->status&RS_OFLO) + { + printk("%s: fifo overflow.\n", dev->name); + mp->stats.rx_errors++; + mp->stats.rx_fifo_errors++; + } + if(mf->status&(RS_CLSN|RS_FRAMERR|RS_FCSERR)) + mp->stats.rx_errors++; + + if(mf->status&RS_CLSN) + mp->stats.collisions++; + if(mf->status&RS_FRAMERR) + mp->stats.rx_frame_errors++; + if(mf->status&RS_FCSERR) + mp->stats.rx_crc_errors++; + + skb = dev_alloc_skb(mf->len+2); + if(skb==NULL) + { + mp->stats.rx_dropped++; + return; + } + skb_reserve(skb,2); + memcpy(skb_put(skb, mf->len), mf->data, mf->len); + + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + mp->stats.rx_packets++; + mp->stats.rx_bytes+=mf->len; +} + +/* + * The PSC has passed us a DMA interrupt event. + */ + +static void mace68k_dma_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + +#if 0 + u32 psc_status; + + /* It seems this must be allowed to stabilise ?? */ + + while((psc_status=psc_read_long(0x0804))!=psc_read_long(0x0804)); + + /* + * Was this an ethernet event ? + */ + + if(psc_status&0x60000000) + { +#endif + /* + * Process the read queue + */ + + u16 psc_status = psc_read_word(PSC_ENETRD_CTL); + + printk("mace68k_dma_intr: PSC_ENETRD_CTL = %04X\n", (uint) psc_status); + + if (psc_status & 0x2000) { + mace68k_rxdma_reset(dev); + mp->rx_done = 0; + } else if (psc_status & 0x100) { + int left; + + psc_write_word(PSC_ENETRD_CMD + mp->rx_slot, 0x1100); + left=psc_read_long(PSC_ENETRD_LEN + mp->rx_slot); + /* read packets */ + + while(mp->rx_done < left) + { + struct mace_frame *mf=((struct mace_frame *) + mp->rx_ring)+mp->rx_done++; + mace_dma_rx_frame(dev, mf); + } + + if(left == 0) /* Out of DMA room */ + { + psc_load_rxdma_base(mp->rx_slot, + (void *)virt_to_phys(mp->rx_ring)); + mp->rx_slot^=16; + mp->rx_done = 0; + } + else + { + psc_write_word(PSC_ENETRD_CMD+mp->rx_slot, + 0x9800); + } + + } + + /* + * Process the write queue + */ + + psc_status = psc_read_word(PSC_ENETWR_CTL); + printk("mace68k_dma_intr: PSC_ENETWR_CTL = %04X\n", (uint) psc_status); + + /* apple's driver seems to loop over this until neither */ + /* condition is true. - jmt */ + + if (psc_status & 0x2000) { + mace68k_txdma_reset(dev); + } else if (psc_status & 0x0100) { + psc_write_word(PSC_ENETWR_CMD + mp->tx_slot, 0x0100); + mp->tx_slot ^=16; + mp->tx_count++; + dev->tbusy = 0; + mark_bh(NET_BH); + } +#if 0 + } +#endif +} diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c index d14ccf3fb..dbb9129d7 100644 --- a/drivers/net/macsonic.c +++ b/drivers/net/macsonic.c @@ -42,153 +42,245 @@ #include <asm/pgtable.h> #include <asm/segment.h> #include <asm/io.h> +#include <asm/hwtest.h> #include <asm/dma.h> #include <asm/macintosh.h> +#include <asm/macints.h> +#include <asm/mac_via.h> #include <linux/errno.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> - -#include <config/macsonic.h> +#include <linux/module.h> #define SREGS_PAD(n) u16 n; #include "sonic.h" -extern int mac_onboard_sonic_probe(void); +static int sonic_debug = 0; +static int sonic_version_printed = 0; -static int setup_debug = -1; -static int setup_offset = -1; -static int setup_shift = -1; +extern int macsonic_probe(struct net_device* dev); +extern int mac_onboard_sonic_probe(struct net_device* dev); +extern int mac_nubus_sonic_probe(struct net_device* dev); -/* - * This seems to be the right default for the Q800 - */ +/* For onboard SONIC */ +#define ONBOARD_SONIC_REGISTERS 0x50F0A000 +#define ONBOARD_SONIC_PROM_BASE 0x50f08000 -static int reg_offset = 0; -static int reg_shift = 0; +enum macsonic_type { + MACSONIC_DUODOCK, + MACSONIC_APPLE, + MACSONIC_APPLE16, + MACSONIC_DAYNA, + MACSONIC_DAYNALINK +}; -/* - * Macros to access SONIC registers - */ - -#define MAC_SONIC_REGISTERS 0x50F0A000 -#define MAC_SONIC_PROM_BASE 0x50f08000 -#define MAC_SONIC_IRQ 9 /* Nubus 9 */ +/* For the built-in SONIC in the Duo Dock */ +#define DUODOCK_SONIC_REGISTERS 0xe10000 +#define DUODOCK_SONIC_PROM_BASE 0xe12000 -/* - * FIXME: We may need to invert the byte ordering. These should - * be ok for other aspects as they are uncached spaces. - * The original macros from jazzsonic.c works for me - * on my LC 630, YMMV /Andreas Ehliar - */ +/* For Apple-style NuBus SONIC */ +#define APPLE_SONIC_REGISTERS 0 +#define APPLE_SONIC_PROM_BASE 0x40000 -#if 0 -#define SONIC_READ(reg) \ - *((volatile unsigned int *)base_addr+((reg)<<2)+2) +/* Daynalink LC SONIC */ +#define DAYNALINK_PROM_BASE 0x400000 -#define SONIC_WRITE(reg,val) \ - *((volatile unsigned int *)base_addr+((reg)<<2)+2) = val -#else -#define SONIC_READ(reg) \ - *((volatile unsigned int *)base_addr+reg) +/* For Dayna-style NuBus SONIC (haven't seen one yet) */ +#define DAYNA_SONIC_REGISTERS 0x180000 +/* This is what OpenBSD says. However, this is definitely in NuBus + ROM space so we should be able to get it by walking the NuBus + resource directories */ +#define DAYNA_SONIC_MAC_ADDR 0xffe004 -#define SONIC_WRITE(reg,val) \ - *((volatile unsigned int *)base_addr+reg) = val -#endif +#define SONIC_READ_PROM(addr) readb(prom_addr+addr) + +int __init macsonic_probe(struct net_device* dev) +{ + int rv; + + /* This will catch fatal stuff like -ENOMEM as well as success */ + if ((rv = mac_onboard_sonic_probe(dev)) != -ENODEV) + return rv; + return mac_nubus_sonic_probe(dev); +} -#define SONIC_READ_PROM(addr) \ - *((volatile unsigned char *)prom_addr+addr) /* - * Function : mac_sonic_setup(char *str, int *ints) - * - * Purpose : booter command line initialization of the overrides array, - * - * Inputs : str - unused, ints - array of integer parameters with ints[0] - * equal to the number of ints. - * - * Currently unused in the new driver; need to add settable parameters to the - * detect function. - * + * For reversing the PROM address */ -void mac_sonic_setup(char *str, int *ints) { - /* Format of macsonic parameter is: - * macsonic=<debug>,<offset>,<shift> - * Negative values mean don't change. - */ - - /* Grmbl... the standard parameter parsing can't handle negative numbers - * :-( So let's do it ourselves! - */ +static unsigned char nibbletab[] = {0, 8, 4, 12, 2, 10, 6, 14, + 1, 9, 5, 13, 3, 11, 7, 15}; - int i = ints[0]+1, fact; +static inline void bit_reverse_addr(unsigned char addr[6]) +{ + int i; - while( str && (isdigit(*str) || *str == '-') && i <= 10) { - if (*str == '-') - fact = -1, ++str; - else - fact = 1; - ints[i++] = simple_strtoul( str, NULL, 0 ) * fact; - if ((str = strchr( str, ',' )) != NULL) - ++str; - } - ints[0] = i-1; - - if (ints[0] < 1) { - printk( "mac_sonic_setup: no arguments!\n" ); - return; - } + for(i = 0; i < 6; i++) + addr[i] = ((nibbletab[addr[i] & 0xf] << 4) | + nibbletab[(addr[i] >> 4) &0xf]); +} + +int __init macsonic_init(struct net_device* dev) +{ + struct sonic_local* lp = (struct sonic_local *)dev->priv; + int i; - if (ints[0] >= 1) { - /* 0 <= n <= 2 */ - if (ints[1] >= 0 && ints[1] <= 8) - setup_debug = ints[1]; - else if (ints[1] > 16) - printk( "mac_sonic_setup: invalid debug level %d !\n", ints[1] ); + /* Allocate the entire chunk of memory for the descriptors. + Note that this cannot cross a 64K boundary. */ + for (i = 0; i < 20; i++) { + unsigned long desc_base, desc_top; + if ((lp->sonic_desc = + kmalloc(SIZEOF_SONIC_DESC + * SONIC_BUS_SCALE(lp->dma_bitmode), GFP_DMA)) == NULL) { + printk(KERN_ERR "%s: couldn't allocate descriptor buffers\n", dev->name); + } + desc_base = (unsigned long) lp->sonic_desc; + desc_top = desc_base + SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode); + if ((desc_top & 0xffff) >= (desc_base & 0xffff)) + break; + /* Hmm. try again (FIXME: does this actually work?) */ + kfree(lp->sonic_desc); + printk(KERN_DEBUG + "%s: didn't get continguous chunk [%08lx - %08lx], trying again\n", + dev->name, desc_base, desc_top); } - if (ints[0] >= 2) { - /* 0 <= n <= 2 */ - if (ints[2] >= 0 && ints[2] <= 16) - setup_offset = ints[2]; - else if (ints[2] > 16) - printk( "mac_sonic_setup: invalid offset %d !\n", ints[2] ); + + if (lp->sonic_desc == NULL) { + printk(KERN_ERR "%s: tried 20 times to allocate descriptor buffers, giving up.\n", + dev->name); + return -ENOMEM; + } + + /* Now set up the pointers to point to the appropriate places */ + lp->cda = lp->sonic_desc; + lp->tda = lp->cda + (SIZEOF_SONIC_CDA * SONIC_BUS_SCALE(lp->dma_bitmode)); + lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS + * SONIC_BUS_SCALE(lp->dma_bitmode)); + lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS + * SONIC_BUS_SCALE(lp->dma_bitmode)); + + /* FIXME, maybe we should use skbs */ + if ((lp->rba = (char *) + kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_DMA)) == NULL) { + printk(KERN_ERR "%s: couldn't allocate receive buffers\n", dev->name); + return -ENOMEM; } - if (ints[0] >= 3) { - /* 0 <= n <= 2 */ - if (ints[3] >= 0 && ints[3] <= 16) - setup_shift = ints[3]; - else if (ints[3] > 16) - printk( "mac_sonic_setup: invalid shift %d !\n", ints[3] ); + + { + int rs, ds; + + /* almost always 12*4096, but let's not take chances */ + rs = ((SONIC_NUM_RRS * SONIC_RBSIZE + 4095) / 4096) * 4096; + /* almost always under a page, but let's not take chances */ + ds = ((SIZEOF_SONIC_DESC + 4095) / 4096) * 4096; + kernel_set_cachemode(lp->rba, rs, IOMAP_NOCACHE_SER); + kernel_set_cachemode(lp->sonic_desc, ds, IOMAP_NOCACHE_SER); } + +#if 0 + flush_cache_all(); +#endif + + dev->open = sonic_open; + dev->stop = sonic_close; + dev->hard_start_xmit = sonic_send_packet; + dev->get_stats = sonic_get_stats; + dev->set_multicast_list = &sonic_multicast_list; + + /* + * clear tally counter + */ + sonic_write(dev, SONIC_CRCT, 0xffff); + sonic_write(dev, SONIC_FAET, 0xffff); + sonic_write(dev, SONIC_MPT, 0xffff); + + /* Fill in the fields of the device structure with ethernet values. */ + ether_setup(dev); + return 0; } -static int sonic_debug = 0; +int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev) +{ + const int prom_addr = ONBOARD_SONIC_PROM_BASE; + int i; -/* - * For reversing the PROM address - */ + /* On NuBus boards we can sometimes look in the ROM resources. + No such luck for comm-slot/onboard. */ + for(i = 0; i < 6; i++) + dev->dev_addr[i] = SONIC_READ_PROM(i); -static unsigned char nibbletab[] = {0, 8, 4, 12, 2, 10, 6, 14, - 1, 9, 5, 13, 3, 11, 7, 15}; + /* Most of the time, the address is bit-reversed. The NetBSD + source has a rather long and detailed historical account of + why this is so. */ + if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) && + memcmp(dev->dev_addr, "\x00\xA0\x40", 3) && + memcmp(dev->dev_addr, "\x00\x05\x02", 3)) + bit_reverse_addr(dev->dev_addr); + else + return 0; + + /* If we still have what seems to be a bogus address, we'll + look in the CAM. The top entry should be ours. */ + /* Danger! This only works if MacOS has already initialized + the card... */ + if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) && + memcmp(dev->dev_addr, "\x00\xA0\x40", 3) && + memcmp(dev->dev_addr, "\x00\x05\x02", 3)) + { + unsigned short val; + + printk(KERN_INFO "macsonic: PROM seems to be wrong, trying CAM entry 15\n"); + + sonic_write(dev, SONIC_CMD, SONIC_CR_RST); + sonic_write(dev, SONIC_CEP, 15); + + val = sonic_read(dev, SONIC_CAP2); + dev->dev_addr[5] = val >> 8; + dev->dev_addr[4] = val & 0xff; + val = sonic_read(dev, SONIC_CAP1); + dev->dev_addr[3] = val >> 8; + dev->dev_addr[2] = val & 0xff; + val = sonic_read(dev, SONIC_CAP0); + dev->dev_addr[1] = val >> 8; + dev->dev_addr[0] = val & 0xff; + + printk(KERN_INFO "HW Address from CAM 15: "); + for (i = 0; i < 6; i++) { + printk("%2.2x", dev->dev_addr[i]); + if (i < 5) + printk(":"); + } + printk("\n"); + } else return 0; -int __init mac_onboard_sonic_probe(void) + if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) && + memcmp(dev->dev_addr, "\x00\xA0\x40", 3) && + memcmp(dev->dev_addr, "\x00\x05\x02", 3)) + { + /* + * Still nonsense ... messed up someplace! + */ + printk(KERN_ERR "macsonic: ERROR (INVALID MAC)\n"); + return -EIO; + } else return 0; +} + +int __init mac_onboard_sonic_probe(struct net_device* dev) { - struct net_device *dev; - unsigned int silicon_revision; - unsigned int val; - struct sonic_local *lp; + /* Bwahahaha */ + static int once_is_more_than_enough = 0; + struct sonic_local* lp; int i; - int base_addr = MAC_SONIC_REGISTERS; - int prom_addr = MAC_SONIC_PROM_BASE; - static int one=0; - if (!MACH_IS_MAC) + if (once_is_more_than_enough) return -ENODEV; + once_is_more_than_enough = 1; - if(++one!=1) /* Only one is allowed */ + if (!MACH_IS_MAC) return -ENODEV; printk(KERN_INFO "Checking for internal Macintosh ethernet (SONIC).. "); @@ -198,288 +290,332 @@ int __init mac_onboard_sonic_probe(void) printk("none.\n"); return -ENODEV; } - - printk("yes\n"); - - if (setup_debug >= 0) - sonic_debug = setup_debug; - /* - * This may depend on the actual Mac model ... works for me. - */ - reg_offset = - (setup_offset >= 0) ? setup_offset : 0; - reg_shift = - (setup_shift >= 0) ? setup_shift : 0; + /* Bogus probing, on the models which may or may not have + Ethernet (BTW, the Ethernet *is* always at the same + address, and nothing else lives there, at least if Apple's + documentation is to be believed) */ + if (macintosh_config->ident == MAC_MODEL_Q630 || + macintosh_config->ident == MAC_MODEL_P588 || + macintosh_config->ident == MAC_MODEL_C610) { + unsigned long flags; + int card_present; + + save_flags(flags); + cli(); + card_present = hwreg_present((void*)ONBOARD_SONIC_REGISTERS); + restore_flags(flags); + + if (!card_present) { + printk("none.\n"); + return -ENODEV; + } + } - /* - * get the Silicon Revision ID. If this is one of the known - * one assume that we found a SONIC ethernet controller at - * the expected location. - * (This is not implemented in the Macintosh driver yet; need - * to collect values from various sources. Mine is 0x4 ...) - */ + printk("yes\n"); - silicon_revision = SONIC_READ(SONIC_SR); - if (sonic_debug > 1) - printk("SONIC Silicon Revision = 0x%04x\n", silicon_revision); + if (dev) { + dev = init_etherdev(dev, sizeof(struct sonic_local)); + /* methinks this will always be true but better safe than sorry */ + if (dev->priv == NULL) + dev->priv = kmalloc(sizeof(struct sonic_local), GFP_KERNEL); + } else { + dev = init_etherdev(NULL, sizeof(struct sonic_local)); + } - /* - * We need to allocate sonic_local later on, making sure it's - * aligned on a 64k boundary. So, no space for dev->priv allocated - * here ... - */ - dev = init_etherdev(0,0); - - if(dev==NULL) + if (dev == NULL) return -ENOMEM; - printk("%s: %s found at 0x%08x, ", - dev->name, "SONIC ethernet", base_addr); + lp = (struct sonic_local*) dev->priv; + memset(lp, 0, sizeof(struct sonic_local)); + /* Danger! My arms are flailing wildly! You *must* set this + before using sonic_read() */ - if (sonic_debug > 1) - printk("using offset %d shift %d,", reg_offset, reg_shift); + dev->base_addr = ONBOARD_SONIC_REGISTERS; + if (via_alt_mapping) + dev->irq = IRQ_AUTO_3; + else + dev->irq = IRQ_NUBUS_9; - /* Fill in the 'dev' fields. */ - dev->base_addr = base_addr; - dev->irq = MAC_SONIC_IRQ; + if (!sonic_version_printed) { + printk(KERN_INFO "%s", version); + sonic_version_printed = 1; + } + printk(KERN_INFO "%s: onboard / comm-slot SONIC at 0x%08lx\n", + dev->name, dev->base_addr); + + /* Now do a song and dance routine in an attempt to determine + the bus width */ + + /* The PowerBook's SONIC is 16 bit always. */ + if (macintosh_config->ident == MAC_MODEL_PB520) { + lp->reg_offset = 0; + lp->dma_bitmode = 0; + } else { + /* Some of the comm-slot cards are 16 bit. But some + of them are not. The 32-bit cards use offset 2 and + pad with zeroes or sometimes ones (I think...) + Therefore, if we try offset 0 and get a silicon + revision of 0, we assume 16 bit. */ + int sr; + + /* Technically this is not necessary since we zeroed + it above */ + lp->reg_offset = 0; + lp->dma_bitmode = 0; + sr = sonic_read(dev, SONIC_SR); + if (sr == 0 || sr == 0xffff) { + lp->reg_offset = 2; + /* 83932 is 0x0004, 83934 is 0x0100 or 0x0101 */ + sr = sonic_read(dev, SONIC_SR); + lp->dma_bitmode = 1; + + } + printk(KERN_INFO + "%s: revision 0x%04x, using %d bit DMA and register offset %d\n", + dev->name, sr, lp->dma_bitmode?32:16, lp->reg_offset); + } - /* - * Put the sonic into software reset, then - * retrieve and print the ethernet address. - */ - SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); + /* Software reset, then initialize control registers. */ + sonic_write(dev, SONIC_CMD, SONIC_CR_RST); + sonic_write(dev, SONIC_DCR, SONIC_DCR_BMS | + SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_EXBUS | + (lp->dma_bitmode ? SONIC_DCR_DW : 0)); + /* This *must* be written back to in order to restore the + extended programmable output bits */ + sonic_write(dev, SONIC_DCR2, 0); - /* - * We can't trust MacOS to initialise things it seems. - */ + /* Clear *and* disable interrupts to be on the safe side */ + sonic_write(dev, SONIC_ISR,0x7fff); + sonic_write(dev, SONIC_IMR,0); - if (sonic_debug > 1) - printk("SONIC_DCR was %X\n",SONIC_READ(SONIC_DCR)); - - SONIC_WRITE(SONIC_DCR, - SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_EXBUS | SONIC_DCR_DW); + /* Now look for the MAC address. */ + if (mac_onboard_sonic_ethernet_addr(dev) != 0) + return -ENODEV; - /* - * We don't want floating spare IRQ's around, not on - * level triggered systems! - * Strange though - writing to the ISR only clears currently - * pending IRQs, but doesn't disable them... Does this make - * a difference?? Seems it does ... - */ -#if 1 - SONIC_WRITE(SONIC_ISR,0x7fff); - SONIC_WRITE(SONIC_IMR,0); -#else - SONIC_WRITE(SONIC_ISR, SONIC_IMR_DEFAULT); -#endif - - /* This is how it is done in jazzsonic.c - * It doesn't seem to work here though. - */ - if (sonic_debug > 2) { - printk("Retreiving CAM entry 0. This should be the HW address.\n"); - - SONIC_WRITE(SONIC_CEP, 0); - for (i = 0; i < 3; i++) - { - val = SONIC_READ(SONIC_CAP0 - i); - dev->dev_addr[i * 2] = val; - dev->dev_addr[i * 2 + 1] = val >> 8; - } + printk(KERN_INFO "MAC "); + for (i = 0; i < 6; i++) { + printk("%2.2x", dev->dev_addr[i]); + if (i < 5) + printk(":"); + } - printk("HW Address from CAM 0: "); - for (i = 0; i < 6; i++) - { - printk("%2.2x", dev->dev_addr[i]); - if (i < 5) - printk(":"); - } - printk("\n"); + printk(" IRQ %d\n", dev->irq); - printk("Retreiving CAM entry 15. Another candidate...\n"); + /* Shared init code */ + return macsonic_init(dev); +} - /* - * MacOS seems to use CAM entry 15 ... - */ - SONIC_WRITE(SONIC_CEP, 15); - for (i = 0; i < 3; i++) - { - val = SONIC_READ(SONIC_CAP0 - i); - dev->dev_addr[i * 2] = val; - dev->dev_addr[i * 2 + 1] = val >> 8; - } +int __init mac_nubus_sonic_ethernet_addr(struct net_device* dev, + unsigned long prom_addr, + int id) +{ + int i; + for(i = 0; i < 6; i++) + dev->dev_addr[i] = SONIC_READ_PROM(i); + /* For now we are going to assume that they're all bit-reversed */ + bit_reverse_addr(dev->dev_addr); - printk("HW Address from CAM 15: "); - for (i = 0; i < 6; i++) - { - printk("%2.2x", dev->dev_addr[i]); - if (i < 5) - printk(":"); - } - printk("\n"); - } + return 0; +} - /* - * if we can read the PROM, we're safe :-) - */ - if (sonic_debug > 1) - printk("Retreiving HW address from the PROM: "); - - for(i=0;i<6;i++){ - dev->dev_addr[i]=SONIC_READ_PROM(i); - } - if (sonic_debug > 1) { - for (i = 0; i < 6; i++) - { - printk("%2.2x", dev->dev_addr[i]); - if (i < 5) - printk(":"); - } - printk("\n"); +int __init macsonic_ident(struct nubus_dev* ndev) +{ + if (ndev->dr_hw == NUBUS_DRHW_ASANTE_LC && + ndev->dr_sw == NUBUS_DRSW_SONIC_LC) + return MACSONIC_DAYNALINK; + if (ndev->dr_hw == NUBUS_DRHW_SONIC && + ndev->dr_sw == NUBUS_DRSW_APPLE) { + /* There has to be a better way to do this... */ + if (strstr(ndev->board->name, "DuoDock")) + return MACSONIC_DUODOCK; + else + return MACSONIC_APPLE; } - /* - * If its not one of these we have - * screwed up on this Mac model - */ + return -1; +} - if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) && - memcmp(dev->dev_addr, "\x00\xA0\x40", 3) && - memcmp(dev->dev_addr, "\x00\x05\x02", 3)) +int __init mac_nubus_sonic_probe(struct net_device* dev) +{ + static int slots = 0; + struct nubus_dev* ndev = NULL; + struct sonic_local* lp; + unsigned long base_addr, prom_addr; + u16 sonic_dcr; + int id; + int i; + int reg_offset, dma_bitmode; + + /* Find the first SONIC that hasn't been initialized already */ + while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, + NUBUS_TYPE_ETHERNET, ndev)) != NULL) { - /* - * Try bit reversed - */ - for(i=0;i<6;i++){ - val = SONIC_READ_PROM(i); - dev->dev_addr[i]=(nibbletab[val & 0xf] << 4) | - nibbletab[(val >> 4) &0xf]; - } - if (sonic_debug > 1) { - printk("Trying bit reversed: "); - for (i = 0; i < 6; i++) - { - printk("%2.2x", dev->dev_addr[i]); - if (i < 5) - printk(":"); - } - printk("\n"); - } - if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) && - memcmp(dev->dev_addr, "\x00\xA0\x40", 3) && - memcmp(dev->dev_addr, "\x00\x05\x02", 3)) - { - /* - * Still nonsense ... messed up someplace! - */ - printk("ERROR (INVALID MAC)\n"); - return -EIO; - } + /* Have we seen it already? */ + if (slots & (1<<ndev->board->slot)) + continue; + slots |= 1<<ndev->board->slot; + + /* Is it one of ours? */ + if ((id = macsonic_ident(ndev)) != -1) + break; } - printk(" MAC "); - for (i = 0; i < 6; i++) - { + if (ndev == NULL) + return -ENODEV; + + switch (id) { + case MACSONIC_DUODOCK: + base_addr = ndev->board->slot_addr + DUODOCK_SONIC_REGISTERS; + prom_addr = ndev->board->slot_addr + DUODOCK_SONIC_PROM_BASE; + sonic_dcr = SONIC_DCR_EXBUS | SONIC_DCR_RFT0 | SONIC_DCR_RFT1 + | SONIC_DCR_TFT0; + reg_offset = 2; + dma_bitmode = 1; + break; + case MACSONIC_APPLE: + base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS; + prom_addr = ndev->board->slot_addr + APPLE_SONIC_PROM_BASE; + sonic_dcr = SONIC_DCR_BMS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0; + reg_offset = 0; + dma_bitmode = 1; + break; + case MACSONIC_APPLE16: + base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS; + prom_addr = ndev->board->slot_addr + APPLE_SONIC_PROM_BASE; + sonic_dcr = SONIC_DCR_EXBUS + | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 + | SONIC_DCR_PO1 | SONIC_DCR_BMS; + reg_offset = 0; + dma_bitmode = 0; + break; + case MACSONIC_DAYNALINK: + base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS; + prom_addr = ndev->board->slot_addr + DAYNALINK_PROM_BASE; + sonic_dcr = SONIC_DCR_RFT1 | SONIC_DCR_TFT0 + | SONIC_DCR_PO1 | SONIC_DCR_BMS; + reg_offset = 0; + dma_bitmode = 0; + break; + case MACSONIC_DAYNA: + base_addr = ndev->board->slot_addr + DAYNA_SONIC_REGISTERS; + prom_addr = ndev->board->slot_addr + DAYNA_SONIC_MAC_ADDR; + sonic_dcr = SONIC_DCR_BMS + | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_PO1; + reg_offset = 0; + dma_bitmode = 0; + break; + default: + printk(KERN_ERR "macsonic: WTF, id is %d\n", id); + return -ENODEV; + } + + if (dev) { + dev = init_etherdev(dev, sizeof(struct sonic_local)); + /* methinks this will always be true but better safe than sorry */ + if (dev->priv == NULL) + dev->priv = kmalloc(sizeof(struct sonic_local), GFP_KERNEL); + } else { + dev = init_etherdev(NULL, sizeof(struct sonic_local)); + } + + if (dev == NULL) + return -ENOMEM; + + lp = (struct sonic_local*) dev->priv; + memset(lp, 0, sizeof(struct sonic_local)); + /* Danger! My arms are flailing wildly! You *must* set this + before using sonic_read() */ + lp->reg_offset = reg_offset; + lp->dma_bitmode = dma_bitmode; + dev->base_addr = base_addr; + dev->irq = SLOT2IRQ(ndev->board->slot); + + if (!sonic_version_printed) { + printk(KERN_INFO "%s", version); + sonic_version_printed = 1; + } + printk(KERN_INFO "%s: %s in slot %X\n", + dev->name, ndev->board->name, ndev->board->slot); + printk(KERN_INFO "%s: revision 0x%04x, using %d bit DMA and register offset %d\n", + dev->name, sonic_read(dev, SONIC_SR), dma_bitmode?32:16, reg_offset); + + /* Software reset, then initialize control registers. */ + sonic_write(dev, SONIC_CMD, SONIC_CR_RST); + sonic_write(dev, SONIC_DCR, sonic_dcr + | (dma_bitmode ? SONIC_DCR_DW : 0)); + + /* Clear *and* disable interrupts to be on the safe side */ + sonic_write(dev, SONIC_ISR,0x7fff); + sonic_write(dev, SONIC_IMR,0); + + /* Now look for the MAC address. */ + if (mac_nubus_sonic_ethernet_addr(dev, prom_addr, id) != 0) + return -ENODEV; + + printk(KERN_INFO "MAC "); + for (i = 0; i < 6; i++) { printk("%2.2x", dev->dev_addr[i]); if (i < 5) printk(":"); } + printk(" IRQ %d\n", dev->irq); - printk(" IRQ %d\n", MAC_SONIC_IRQ); - - /* Initialize the device structure. */ - if (dev->priv == NULL) - { - if (sonic_debug > 2) { - printk("Allocating memory for dev->priv aka lp\n"); - printk("Memory to allocate: %d\n",sizeof(*lp)); - } - /* - * the memory be located in the same 64kb segment - */ - lp = NULL; - i = 0; - do - { - lp = (struct sonic_local *) kmalloc(sizeof(*lp), GFP_KERNEL); - if ((unsigned long) lp >> 16 != ((unsigned long) lp + sizeof(*lp)) >> 16) - { - /* FIXME, free the memory later */ - kfree(lp); - lp = NULL; - } - } - while (lp == NULL && i++ < 20); + /* Shared init code */ + return macsonic_init(dev); +} - if (lp == NULL) - { - printk("%s: couldn't allocate memory for descriptors\n", - dev->name); - return -ENOMEM; - } +#ifdef MODULE +static char namespace[16] = ""; +static struct net_device dev_macsonic = { + NULL, + 0, 0, 0, 0, + 0, 0, + 0, 0, 0, NULL, NULL }; - if (sonic_debug > 2) { - printk("Memory allocated after %d tries\n",i); - } +MODULE_PARM(sonic_debug, "i"); - /* XXX sonic_local has the TDA, RRA, RDA, don't cache */ - kernel_set_cachemode((u32)lp, 8192, IOMAP_NOCACHE_SER); - memset(lp, 0, sizeof(struct sonic_local)); +EXPORT_NO_SYMBOLS; - lp->cda_laddr = (u32)lp; - if (sonic_debug > 2) { - printk("memory allocated for sonic at 0x%x\n",lp); - } - lp->tda_laddr = lp->cda_laddr + sizeof(lp->cda); - lp->rra_laddr = lp->tda_laddr + sizeof(lp->tda); - lp->rda_laddr = lp->rra_laddr + sizeof(lp->rra); - - /* allocate receive buffer area */ - /* FIXME, maybe we should use skbs */ - if ((lp->rba = (char *) kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL)) == NULL) - { - printk("%s: couldn't allocate receive buffers\n", dev->name); - return -ENOMEM; - } - /* XXX RBA written by Sonic, not cached either */ - kernel_set_cachemode((u32)lp->rba, 6*8192, IOMAP_NOCACHE_SER); - lp->rba_laddr = (u32)lp->rba; - flush_cache_all(); - dev->priv = (struct sonic_local *) lp; - } - lp = (struct sonic_local *) dev->priv; - dev->open = sonic_open; - dev->stop = sonic_close; - dev->hard_start_xmit = sonic_send_packet; - dev->get_stats = sonic_get_stats; - dev->set_multicast_list = &sonic_multicast_list; +int +init_module(void) +{ + dev_macsonic.name = namespace; + dev_macsonic.init = macsonic_probe; - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); + if (register_netdev(&dev_macsonic) != 0) { + printk(KERN_WARNING "macsonic.c: No card found\n"); + return -ENXIO; + } return 0; } -/* - * SONIC uses a nubus IRQ - */ +void +cleanup_module(void) +{ + if (dev_macsonic.priv != NULL) { + unregister_netdev(&dev_macsonic); + kfree(dev_macsonic.priv); + dev_macsonic.priv = NULL; + } +} +#endif /* MODULE */ -#define sonic_request_irq(irq, vec, flags, name, dev) \ - nubus_request_irq(irq, dev, vec) -#define sonic_free_irq(irq,id) nubus_free_irq(irq) -/* - * No funnies on memory mapping. - */ +#define vdma_alloc(foo, bar) ((u32)foo) +#define vdma_free(baz) +#define sonic_chiptomem(bat) (bat) +#define PHYSADDR(quux) (quux) -#define sonic_chiptomem(x) (x) +#include "sonic.c" /* - * No VDMA on a Macintosh. So we need request no such facility. + * Local variables: + * compile-command: "m68k-linux-gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -ffixed-a2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c -o macsonic.o macsonic.c" + * version-control: t + * kept-new-versions: 5 + * c-indent-level: 8 + * tab-width: 8 + * End: + * */ - -#define vdma_alloc(x,y) ((u32)(x)) -#define vdma_free(x) -#define PHYSADDR(x) (x) - -#include "sonic.c" diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index 4fff08b7f..006e36f4b 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -21,7 +21,7 @@ */ -static char *version = "sun3lance.c: v1.0 12/12/96 Sam Creasey (sammy@users.qual.net)\n"; +static char *version = "sun3lance.c: v1.1 11/17/1999 Sam Creasey (sammy@oh.verio.com)\n"; #include <linux/module.h> @@ -263,6 +263,8 @@ static int __init lance_probe( struct net_device *dev) int i; static int did_version = 0; int found = 0; + volatile unsigned short *ioaddr_probe; + unsigned short tmp1, tmp2; /* LANCE_OBIO can be found within the IO pmeg with some effort */ for(ioaddr = 0xfe00000; ioaddr < (0xfe00000 + @@ -282,6 +284,23 @@ static int __init lance_probe( struct net_device *dev) if(!found) return 0; + /* test to see if there's really a lance here */ + /* (CSRO_INIT shouldn't be readable) */ + + ioaddr_probe = (volatile unsigned short *)ioaddr; + tmp1 = ioaddr_probe[0]; + tmp2 = ioaddr_probe[1]; + + ioaddr_probe[1] = CSR0; + ioaddr_probe[0] = CSR0_INIT | CSR0_STOP; + + if(ioaddr_probe[0] != CSR0_STOP) { + ioaddr_probe[0] = tmp1; + ioaddr_probe[1] = tmp2; + + return 0; + } + init_etherdev( dev, sizeof(struct lance_private) ); if (!dev->priv) dev->priv = kmalloc( sizeof(struct lance_private), GFP_KERNEL ); diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index 10e466a5d..b86c8fdb6 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -1,4 +1,4 @@ -/* $Id: sunbmac.c,v 1.12 1999/12/15 14:07:58 davem Exp $ +/* $Id: sunbmac.c,v 1.13 2000/01/28 13:42:29 jj Exp $ * sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index eb76a9fee..65d8315d9 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -1,4 +1,4 @@ -/* $Id: sunhme.c,v 1.84 1999/12/15 14:08:03 davem Exp $ +/* $Id: sunhme.c,v 1.85 2000/01/28 13:42:27 jj Exp $ * sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching, * auto carrier detecting ethernet driver. Also known as the * "Happy Meal Ethernet" found on SunSwift SBUS cards. diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 3c499ba38..45b671ae7 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -1,4 +1,4 @@ -/* $Id: sunlance.c,v 1.92 1999/12/15 14:08:09 davem Exp $ +/* $Id: sunlance.c,v 1.93 2000/01/28 13:42:31 jj Exp $ * lance.c: Linux/Sparc/Lance driver * * Written 1995, 1996 by Miguel de Icaza diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index 2a170a0a6..53e0c756f 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -1,4 +1,4 @@ -/* $Id: sunqe.c,v 1.40 1999/12/15 14:08:13 davem Exp $ +/* $Id: sunqe.c,v 1.41 2000/01/28 13:42:30 jj Exp $ * sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver. * Once again I am out to prove that every ethernet * controller out there can be most efficiently programmed |