Messages in this thread Patch in this message | | | Date | Mon, 22 Dec 2003 17:21:02 +0000 | From | Russell King <> | Subject | [PATCH] PCMCIA updates |
| |
Here's a patch covering a forward-port of a couple of changes from David Hinds to 2.6. I've tested them, and the ISA/PCI irq fix has been independently tested.
I'm also sending this to Linus/akpm shortly.
| [PCMCIA] fix ISA/PCI interrupt allocation | | Patch from David Hinds | | This is a forward port of a patch for 2.4. This changes interrupt | allocation for 16-bit cards so that if ISA interrupts are all in | use, the bridge's PCI interrupt will be used. | | [PCMCIA] fix half/full duplex selection for pcnet_cs driver | | Patch from David Hinds. | | Another forward port from 2.4; this fixes full/half duplex selection | for certain DL10019 based cards.
diff -Nru a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c --- a/drivers/net/pcmcia/pcnet_cs.c Mon Dec 22 17:16:34 2003 +++ b/drivers/net/pcmcia/pcnet_cs.c Mon Dec 22 17:16:34 2003 @@ -11,7 +11,7 @@ Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net - pcnet_cs.c 1.149 2002/06/29 06:27:37 + pcnet_cs.c 1.153 2003/11/09 18:53:09 The network driver code is based on Donald Becker's NE2000 code: @@ -74,7 +74,7 @@ MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"pcnet_cs.c 1.149 2002/06/29 06:27:37 (David Hinds)"; +"pcnet_cs.c 1.153 2003/11/09 18:53:09 (David Hinds)"; #else #define DEBUG(n, args...) #endif @@ -871,13 +871,15 @@ MII interface support for DL10019 and DL10022 based cards - On the DL10019, the MII IO direction bit is 0x10; on the DL10022 + On the DL10019, the MII IO direction bit is 0x10; on the DL10022 it is 0x20. Setting both bits seems to work on both card types. ======================================================================*/ #define DLINK_GPIO 0x1c #define DLINK_DIAG 0x1d +#define DLINK_EEPROM 0x1e + #define MDIO_SHIFT_CLK 0x80 #define MDIO_DATA_OUT 0x40 #define MDIO_DIR_WRITE 0x30 @@ -940,6 +942,98 @@ outb_p(0x00, addr); } +/*====================================================================== + + EEPROM access routines for DL10019 and DL10022 based cards + +======================================================================*/ + +#define EE_EEP 0x40 +#define EE_ASIC 0x10 +#define EE_CS 0x08 +#define EE_CK 0x04 +#define EE_DO 0x02 +#define EE_DI 0x01 +#define EE_ADOT 0x01 /* DataOut for ASIC */ +#define EE_READ_CMD 0x06 + +#define DL19FDUPLX 0x0400 /* DL10019 Full duplex mode */ + +static int read_eeprom(ioaddr_t ioaddr, int location) +{ + int i, retval = 0; + ioaddr_t ee_addr = ioaddr + DLINK_EEPROM; + int read_cmd = location | (EE_READ_CMD << 8); + + outb(0, ee_addr); + outb(EE_EEP|EE_CS, ee_addr); + + /* Shift the read command bits out. */ + for (i = 10; i >= 0; i--) { + short dataval = (read_cmd & (1 << i)) ? EE_DO : 0; + outb_p(EE_EEP|EE_CS|dataval, ee_addr); + outb_p(EE_EEP|EE_CS|dataval|EE_CK, ee_addr); + } + outb(EE_EEP|EE_CS, ee_addr); + + for (i = 16; i > 0; i--) { + outb_p(EE_EEP|EE_CS | EE_CK, ee_addr); + retval = (retval << 1) | ((inb(ee_addr) & EE_DI) ? 1 : 0); + outb_p(EE_EEP|EE_CS, ee_addr); + } + + /* Terminate the EEPROM access. */ + outb(0, ee_addr); + return retval; +} + +/* + The internal ASIC registers can be changed by EEPROM READ access + with EE_ASIC bit set. + In ASIC mode, EE_ADOT is used to output the data to the ASIC. +*/ + +static void write_asic(ioaddr_t ioaddr, int location, short asic_data) +{ + int i; + ioaddr_t ee_addr = ioaddr + DLINK_EEPROM; + short dataval; + int read_cmd = location | (EE_READ_CMD << 8); + + asic_data |= read_eeprom(ioaddr, location); + + outb(0, ee_addr); + outb(EE_ASIC|EE_CS|EE_DI, ee_addr); + + read_cmd = read_cmd >> 1; + + /* Shift the read command bits out. */ + for (i = 9; i >= 0; i--) { + dataval = (read_cmd & (1 << i)) ? EE_DO : 0; + outb_p(EE_ASIC|EE_CS|EE_DI|dataval, ee_addr); + outb_p(EE_ASIC|EE_CS|EE_DI|dataval|EE_CK, ee_addr); + outb_p(EE_ASIC|EE_CS|EE_DI|dataval, ee_addr); + } + // sync + outb(EE_ASIC|EE_CS, ee_addr); + outb(EE_ASIC|EE_CS|EE_CK, ee_addr); + outb(EE_ASIC|EE_CS, ee_addr); + + for (i = 15; i >= 0; i--) { + dataval = (asic_data & (1 << i)) ? EE_ADOT : 0; + outb_p(EE_ASIC|EE_CS|dataval, ee_addr); + outb_p(EE_ASIC|EE_CS|dataval|EE_CK, ee_addr); + outb_p(EE_ASIC|EE_CS|dataval, ee_addr); + } + + /* Terminate the ASIC access. */ + outb(EE_ASIC|EE_DI, ee_addr); + outb(EE_ASIC|EE_DI| EE_CK, ee_addr); + outb(EE_ASIC|EE_DI, ee_addr); + + outb(0, ee_addr); +} + /*====================================================================*/ static void set_misc_reg(struct net_device *dev) @@ -1154,6 +1248,9 @@ if (link && (info->flags & IS_DL10022)) { /* Disable collision detection on full duplex links */ outb((p & 0x0140) ? 4 : 0, nic_base + DLINK_DIAG); + } else if (link && (info->flags & IS_DL10019)) { + /* Disable collision detection on full duplex links */ + write_asic(dev->base_addr, 4, (p & 0x140) ? DL19FDUPLX : 0); } if (link) { if (info->phy_id == info->eth_phy) { diff -Nru a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c --- a/drivers/pcmcia/cs.c Mon Dec 22 17:16:34 2003 +++ b/drivers/pcmcia/cs.c Mon Dec 22 17:16:34 2003 @@ -1916,7 +1916,7 @@ { struct pcmcia_socket *s; config_t *c; - int ret = 0, irq = 0; + int ret = CS_IN_USE, irq = 0; if (CHECK_HANDLE(handle)) return CS_BAD_HANDLE; @@ -1928,13 +1928,9 @@ return CS_CONFIGURATION_LOCKED; if (c->state & CONFIG_IRQ_REQ) return CS_IN_USE; - - /* Short cut: if there are no ISA interrupts, then it is PCI */ - if (!s->irq_mask) { - irq = s->pci_irq; - ret = (irq) ? 0 : CS_IN_USE; + #ifdef CONFIG_PCMCIA_PROBE - } else if (s->irq.AssignedIRQ != 0) { + if (s->irq.AssignedIRQ != 0) { /* If the interrupt is already assigned, it must match */ irq = s->irq.AssignedIRQ; if (req->IRQInfo1 & IRQ_INFO2_VALID) { @@ -1943,7 +1939,6 @@ } else ret = ((req->IRQInfo1&IRQ_MASK) == irq) ? 0 : CS_BAD_ARGS; } else { - ret = CS_IN_USE; if (req->IRQInfo1 & IRQ_INFO2_VALID) { u_int try, mask = req->IRQInfo2 & s->irq_mask; for (try = 0; try < 2; try++) { @@ -1958,12 +1953,13 @@ irq = req->IRQInfo1 & IRQ_MASK; ret = try_irq(req->Attributes, irq, 1); } -#else - } else { - ret = CS_UNSUPPORTED_MODE; + } #endif + if (ret != 0) { + if (!s->pci_irq) + return ret; + irq = s->pci_irq; } - if (ret != 0) return ret; if (req->Attributes & IRQ_HANDLE_PRESENT) { if (request_irq(irq, req->Handler, -- Russell King Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/ maintainer of: 2.6 PCMCIA - http://pcmcia.arm.linux.org.uk/ 2.6 Serial core - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |