cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

apne.c (17254B)


      1/*
      2 * Amiga Linux/68k 8390 based PCMCIA Ethernet Driver for the Amiga 1200
      3 *
      4 * (C) Copyright 1997 Alain Malek
      5 *                    (Alain.Malek@cryogen.com)
      6 *
      7 * ----------------------------------------------------------------------------
      8 *
      9 * This program is based on
     10 *
     11 * ne.c:       A general non-shared-memory NS8390 ethernet driver for linux
     12 *             Written 1992-94 by Donald Becker.
     13 *
     14 * 8390.c:     A general NS8390 ethernet driver core for linux.
     15 *             Written 1992-94 by Donald Becker.
     16 *
     17 * cnetdevice: A Sana-II ethernet driver for AmigaOS
     18 *             Written by Bruce Abbott (bhabbott@inhb.co.nz)
     19 *
     20 * ----------------------------------------------------------------------------
     21 *
     22 * This file is subject to the terms and conditions of the GNU General Public
     23 * License.  See the file COPYING in the main directory of the Linux
     24 * distribution for more details.
     25 *
     26 * ----------------------------------------------------------------------------
     27 *
     28 */
     29
     30
     31#include <linux/module.h>
     32#include <linux/kernel.h>
     33#include <linux/errno.h>
     34#include <linux/pci.h>
     35#include <linux/init.h>
     36#include <linux/delay.h>
     37#include <linux/netdevice.h>
     38#include <linux/etherdevice.h>
     39#include <linux/interrupt.h>
     40#include <linux/jiffies.h>
     41
     42#include <asm/io.h>
     43#include <asm/setup.h>
     44#include <asm/amigaints.h>
     45#include <asm/amigahw.h>
     46#include <asm/amigayle.h>
     47#include <asm/amipcmcia.h>
     48
     49#include "8390.h"
     50
     51/* ---- No user-serviceable parts below ---- */
     52
     53#define DRV_NAME "apne"
     54
     55#define NE_BASE	 (dev->base_addr)
     56#define NE_CMD	 		0x00
     57#define NE_DATAPORT		0x10            /* NatSemi-defined port window offset. */
     58#define NE_RESET		0x1f            /* Issue a read to reset, a write to clear. */
     59#define NE_IO_EXTENT	        0x20
     60
     61#define NE_EN0_ISR		0x07
     62#define NE_EN0_DCFG		0x0e
     63
     64#define NE_EN0_RSARLO	        0x08
     65#define NE_EN0_RSARHI	        0x09
     66#define NE_EN0_RCNTLO	        0x0a
     67#define NE_EN0_RXCR		0x0c
     68#define NE_EN0_TXCR		0x0d
     69#define NE_EN0_RCNTHI	        0x0b
     70#define NE_EN0_IMR		0x0f
     71
     72#define NE1SM_START_PG	0x20	/* First page of TX buffer */
     73#define NE1SM_STOP_PG 	0x40	/* Last page +1 of RX ring */
     74#define NESM_START_PG	0x40	/* First page of TX buffer */
     75#define NESM_STOP_PG	0x80	/* Last page +1 of RX ring */
     76
     77
     78static int apne_probe1(struct net_device *dev, int ioaddr);
     79
     80static void apne_reset_8390(struct net_device *dev);
     81static void apne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
     82			  int ring_page);
     83static void apne_block_input(struct net_device *dev, int count,
     84								struct sk_buff *skb, int ring_offset);
     85static void apne_block_output(struct net_device *dev, const int count,
     86							const unsigned char *buf, const int start_page);
     87static irqreturn_t apne_interrupt(int irq, void *dev_id);
     88
     89static int init_pcmcia(void);
     90
     91/* IO base address used for nic */
     92
     93#define IOBASE 0x300
     94
     95/*
     96   use MANUAL_CONFIG and MANUAL_OFFSET for enabling IO by hand
     97   you can find the values to use by looking at the cnet.device
     98   config file example (the default values are for the CNET40BC card)
     99*/
    100
    101/*
    102#define MANUAL_CONFIG 0x20
    103#define MANUAL_OFFSET 0x3f8
    104
    105#define MANUAL_HWADDR0 0x00
    106#define MANUAL_HWADDR1 0x12
    107#define MANUAL_HWADDR2 0x34
    108#define MANUAL_HWADDR3 0x56
    109#define MANUAL_HWADDR4 0x78
    110#define MANUAL_HWADDR5 0x9a
    111*/
    112
    113static const char version[] =
    114    "apne.c:v1.1 7/10/98 Alain Malek (Alain.Malek@cryogen.ch)\n";
    115
    116static int apne_owned;	/* signal if card already owned */
    117
    118static u32 apne_msg_enable;
    119module_param_named(msg_enable, apne_msg_enable, uint, 0444);
    120MODULE_PARM_DESC(msg_enable, "Debug message level (see linux/netdevice.h for bitmap)");
    121
    122static struct net_device * __init apne_probe(void)
    123{
    124	struct net_device *dev;
    125	struct ei_device *ei_local;
    126
    127#ifndef MANUAL_CONFIG
    128	char tuple[8];
    129#endif
    130	int err;
    131
    132	if (!MACH_IS_AMIGA)
    133		return ERR_PTR(-ENODEV);
    134
    135	if (apne_owned)
    136		return ERR_PTR(-ENODEV);
    137
    138	if ( !(AMIGAHW_PRESENT(PCMCIA)) )
    139		return ERR_PTR(-ENODEV);
    140
    141	pr_info("Looking for PCMCIA ethernet card : ");
    142
    143	/* check if a card is inserted */
    144	if (!(PCMCIA_INSERTED)) {
    145		pr_cont("NO PCMCIA card inserted\n");
    146		return ERR_PTR(-ENODEV);
    147	}
    148
    149	dev = alloc_ei_netdev();
    150	if (!dev)
    151		return ERR_PTR(-ENOMEM);
    152	ei_local = netdev_priv(dev);
    153	ei_local->msg_enable = apne_msg_enable;
    154
    155	/* disable pcmcia irq for readtuple */
    156	pcmcia_disable_irq();
    157
    158#ifndef MANUAL_CONFIG
    159	if ((pcmcia_copy_tuple(CISTPL_FUNCID, tuple, 8) < 3) ||
    160		(tuple[2] != CISTPL_FUNCID_NETWORK)) {
    161		pr_cont("not an ethernet card\n");
    162		/* XXX: shouldn't we re-enable irq here? */
    163		free_netdev(dev);
    164		return ERR_PTR(-ENODEV);
    165	}
    166#endif
    167
    168	pr_cont("ethernet PCMCIA card inserted\n");
    169
    170	if (!init_pcmcia()) {
    171		/* XXX: shouldn't we re-enable irq here? */
    172		free_netdev(dev);
    173		return ERR_PTR(-ENODEV);
    174	}
    175
    176	if (!request_region(IOBASE, 0x20, DRV_NAME)) {
    177		free_netdev(dev);
    178		return ERR_PTR(-EBUSY);
    179	}
    180
    181	err = apne_probe1(dev, IOBASE);
    182	if (err) {
    183		release_region(IOBASE, 0x20);
    184		free_netdev(dev);
    185		return ERR_PTR(err);
    186	}
    187	err = register_netdev(dev);
    188	if (!err)
    189		return dev;
    190
    191	pcmcia_disable_irq();
    192	free_irq(IRQ_AMIGA_PORTS, dev);
    193	pcmcia_reset();
    194	release_region(IOBASE, 0x20);
    195	free_netdev(dev);
    196	return ERR_PTR(err);
    197}
    198
    199static int __init apne_probe1(struct net_device *dev, int ioaddr)
    200{
    201    int i;
    202    unsigned char SA_prom[32];
    203    int wordlength = 2;
    204    const char *name = NULL;
    205    int start_page, stop_page;
    206#ifndef MANUAL_HWADDR0
    207    int neX000, ctron;
    208#endif
    209    static unsigned version_printed;
    210
    211    if ((apne_msg_enable & NETIF_MSG_DRV) && (version_printed++ == 0))
    212		netdev_info(dev, version);
    213
    214    netdev_info(dev, "PCMCIA NE*000 ethercard probe");
    215
    216    /* Reset card. Who knows what dain-bramaged state it was left in. */
    217    {	unsigned long reset_start_time = jiffies;
    218
    219	outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET);
    220
    221	while ((inb(ioaddr + NE_EN0_ISR) & ENISR_RESET) == 0)
    222		if (time_after(jiffies, reset_start_time + 2*HZ/100)) {
    223			pr_cont(" not found (no reset ack).\n");
    224			return -ENODEV;
    225		}
    226
    227	outb(0xff, ioaddr + NE_EN0_ISR);		/* Ack all intr. */
    228    }
    229
    230#ifndef MANUAL_HWADDR0
    231
    232    /* Read the 16 bytes of station address PROM.
    233       We must first initialize registers, similar to NS8390_init(eifdev, 0).
    234       We can't reliably read the SAPROM address without this.
    235       (I learned the hard way!). */
    236    {
    237	struct {unsigned long value, offset; } program_seq[] = {
    238	    {E8390_NODMA+E8390_PAGE0+E8390_STOP, NE_CMD}, /* Select page 0*/
    239	    {0x48,	NE_EN0_DCFG},	/* Set byte-wide (0x48) access. */
    240	    {0x00,	NE_EN0_RCNTLO},	/* Clear the count regs. */
    241	    {0x00,	NE_EN0_RCNTHI},
    242	    {0x00,	NE_EN0_IMR},	/* Mask completion irq. */
    243	    {0xFF,	NE_EN0_ISR},
    244	    {E8390_RXOFF, NE_EN0_RXCR},	/* 0x20  Set to monitor */
    245	    {E8390_TXOFF, NE_EN0_TXCR},	/* 0x02  and loopback mode. */
    246	    {32,	NE_EN0_RCNTLO},
    247	    {0x00,	NE_EN0_RCNTHI},
    248	    {0x00,	NE_EN0_RSARLO},	/* DMA starting at 0x0000. */
    249	    {0x00,	NE_EN0_RSARHI},
    250	    {E8390_RREAD+E8390_START, NE_CMD},
    251	};
    252	for (i = 0; i < ARRAY_SIZE(program_seq); i++) {
    253	    outb(program_seq[i].value, ioaddr + program_seq[i].offset);
    254	}
    255
    256    }
    257    for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) {
    258	SA_prom[i] = inb(ioaddr + NE_DATAPORT);
    259	SA_prom[i+1] = inb(ioaddr + NE_DATAPORT);
    260	if (SA_prom[i] != SA_prom[i+1])
    261	    wordlength = 1;
    262    }
    263
    264    /*	At this point, wordlength *only* tells us if the SA_prom is doubled
    265	up or not because some broken PCI cards don't respect the byte-wide
    266	request in program_seq above, and hence don't have doubled up values.
    267	These broken cards would otherwise be detected as an ne1000.  */
    268
    269    if (wordlength == 2)
    270	for (i = 0; i < 16; i++)
    271		SA_prom[i] = SA_prom[i+i];
    272
    273    if (wordlength == 2) {
    274	/* We must set the 8390 for word mode. */
    275	outb(0x49, ioaddr + NE_EN0_DCFG);
    276	start_page = NESM_START_PG;
    277	stop_page = NESM_STOP_PG;
    278    } else {
    279	start_page = NE1SM_START_PG;
    280	stop_page = NE1SM_STOP_PG;
    281    }
    282
    283    neX000 = (SA_prom[14] == 0x57  &&  SA_prom[15] == 0x57);
    284    ctron =  (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d);
    285
    286    /* Set up the rest of the parameters. */
    287    if (neX000) {
    288	name = (wordlength == 2) ? "NE2000" : "NE1000";
    289    } else if (ctron) {
    290	name = (wordlength == 2) ? "Ctron-8" : "Ctron-16";
    291	start_page = 0x01;
    292	stop_page = (wordlength == 2) ? 0x40 : 0x20;
    293    } else {
    294	pr_cont(" not found.\n");
    295	return -ENXIO;
    296
    297    }
    298
    299#else
    300    wordlength = 2;
    301    /* We must set the 8390 for word mode. */
    302    outb(0x49, ioaddr + NE_EN0_DCFG);
    303    start_page = NESM_START_PG;
    304    stop_page = NESM_STOP_PG;
    305
    306    SA_prom[0] = MANUAL_HWADDR0;
    307    SA_prom[1] = MANUAL_HWADDR1;
    308    SA_prom[2] = MANUAL_HWADDR2;
    309    SA_prom[3] = MANUAL_HWADDR3;
    310    SA_prom[4] = MANUAL_HWADDR4;
    311    SA_prom[5] = MANUAL_HWADDR5;
    312    name = "NE2000";
    313#endif
    314
    315    dev->base_addr = ioaddr;
    316    dev->irq = IRQ_AMIGA_PORTS;
    317    dev->netdev_ops = &ei_netdev_ops;
    318
    319    /* Install the Interrupt handler */
    320    i = request_irq(dev->irq, apne_interrupt, IRQF_SHARED, DRV_NAME, dev);
    321    if (i) return i;
    322
    323    eth_hw_addr_set(dev, SA_prom);
    324
    325    pr_cont(" %pM\n", dev->dev_addr);
    326
    327    netdev_info(dev, "%s found.\n", name);
    328
    329    ei_status.name = name;
    330    ei_status.tx_start_page = start_page;
    331    ei_status.stop_page = stop_page;
    332    ei_status.word16 = (wordlength == 2);
    333
    334    ei_status.rx_start_page = start_page + TX_PAGES;
    335
    336    ei_status.reset_8390 = &apne_reset_8390;
    337    ei_status.block_input = &apne_block_input;
    338    ei_status.block_output = &apne_block_output;
    339    ei_status.get_8390_hdr = &apne_get_8390_hdr;
    340
    341    NS8390_init(dev, 0);
    342
    343    pcmcia_ack_int(pcmcia_get_intreq());		/* ack PCMCIA int req */
    344    pcmcia_enable_irq();
    345
    346    apne_owned = 1;
    347
    348    return 0;
    349}
    350
    351/* Hard reset the card.  This used to pause for the same period that a
    352   8390 reset command required, but that shouldn't be necessary. */
    353static void
    354apne_reset_8390(struct net_device *dev)
    355{
    356    unsigned long reset_start_time = jiffies;
    357    struct ei_device *ei_local = netdev_priv(dev);
    358
    359    init_pcmcia();
    360
    361    netif_dbg(ei_local, hw, dev, "resetting the 8390 t=%ld...\n", jiffies);
    362
    363    outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET);
    364
    365    ei_status.txing = 0;
    366    ei_status.dmaing = 0;
    367
    368    /* This check _should_not_ be necessary, omit eventually. */
    369    while ((inb(NE_BASE+NE_EN0_ISR) & ENISR_RESET) == 0)
    370	if (time_after(jiffies, reset_start_time + 2*HZ/100)) {
    371		netdev_err(dev, "ne_reset_8390() did not complete.\n");
    372		break;
    373	}
    374    outb(ENISR_RESET, NE_BASE + NE_EN0_ISR);	/* Ack intr. */
    375}
    376
    377/* Grab the 8390 specific header. Similar to the block_input routine, but
    378   we don't need to be concerned with ring wrap as the header will be at
    379   the start of a page, so we optimize accordingly. */
    380
    381static void
    382apne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
    383{
    384
    385    int nic_base = dev->base_addr;
    386    int cnt;
    387    char *ptrc;
    388    short *ptrs;
    389
    390    /* This *shouldn't* happen. If it does, it's the last thing you'll see */
    391    if (ei_status.dmaing) {
    392	netdev_err(dev, "DMAing conflict in ne_get_8390_hdr "
    393		   "[DMAstat:%d][irqlock:%d][intr:%d].\n",
    394		   ei_status.dmaing, ei_status.irqlock, dev->irq);
    395	return;
    396    }
    397
    398    ei_status.dmaing |= 0x01;
    399    outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
    400    outb(ENISR_RDC, nic_base + NE_EN0_ISR);
    401    outb(sizeof(struct e8390_pkt_hdr), nic_base + NE_EN0_RCNTLO);
    402    outb(0, nic_base + NE_EN0_RCNTHI);
    403    outb(0, nic_base + NE_EN0_RSARLO);		/* On page boundary */
    404    outb(ring_page, nic_base + NE_EN0_RSARHI);
    405    outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
    406
    407    if (ei_status.word16) {
    408        ptrs = (short*)hdr;
    409        for(cnt = 0; cnt < (sizeof(struct e8390_pkt_hdr)>>1); cnt++)
    410            *ptrs++ = inw(NE_BASE + NE_DATAPORT);
    411    } else {
    412        ptrc = (char*)hdr;
    413        for(cnt = 0; cnt < sizeof(struct e8390_pkt_hdr); cnt++)
    414            *ptrc++ = inb(NE_BASE + NE_DATAPORT);
    415    }
    416
    417    outb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
    418    ei_status.dmaing &= ~0x01;
    419
    420    le16_to_cpus(&hdr->count);
    421}
    422
    423/* Block input and output, similar to the Crynwr packet driver.  If you
    424   are porting to a new ethercard, look at the packet driver source for hints.
    425   The NEx000 doesn't share the on-board packet memory -- you have to put
    426   the packet out through the "remote DMA" dataport using outb. */
    427
    428static void
    429apne_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
    430{
    431    int nic_base = dev->base_addr;
    432    char *buf = skb->data;
    433    char *ptrc;
    434    short *ptrs;
    435    int cnt;
    436
    437    /* This *shouldn't* happen. If it does, it's the last thing you'll see */
    438    if (ei_status.dmaing) {
    439		netdev_err(dev, "DMAing conflict in ne_block_input "
    440			   "[DMAstat:%d][irqlock:%d][intr:%d].\n",
    441			   ei_status.dmaing, ei_status.irqlock, dev->irq);
    442	return;
    443    }
    444    ei_status.dmaing |= 0x01;
    445    outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
    446    outb(ENISR_RDC, nic_base + NE_EN0_ISR);
    447    outb(count & 0xff, nic_base + NE_EN0_RCNTLO);
    448    outb(count >> 8, nic_base + NE_EN0_RCNTHI);
    449    outb(ring_offset & 0xff, nic_base + NE_EN0_RSARLO);
    450    outb(ring_offset >> 8, nic_base + NE_EN0_RSARHI);
    451    outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
    452    if (ei_status.word16) {
    453      ptrs = (short*)buf;
    454      for (cnt = 0; cnt < (count>>1); cnt++)
    455        *ptrs++ = inw(NE_BASE + NE_DATAPORT);
    456      if (count & 0x01) {
    457	buf[count-1] = inb(NE_BASE + NE_DATAPORT);
    458      }
    459    } else {
    460      ptrc = buf;
    461      for (cnt = 0; cnt < count; cnt++)
    462        *ptrc++ = inb(NE_BASE + NE_DATAPORT);
    463    }
    464
    465    outb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
    466    ei_status.dmaing &= ~0x01;
    467}
    468
    469static void
    470apne_block_output(struct net_device *dev, int count,
    471		const unsigned char *buf, const int start_page)
    472{
    473    int nic_base = NE_BASE;
    474    unsigned long dma_start;
    475    char *ptrc;
    476    short *ptrs;
    477    int cnt;
    478
    479    /* Round the count up for word writes.  Do we need to do this?
    480       What effect will an odd byte count have on the 8390?
    481       I should check someday. */
    482    if (ei_status.word16 && (count & 0x01))
    483      count++;
    484
    485    /* This *shouldn't* happen. If it does, it's the last thing you'll see */
    486    if (ei_status.dmaing) {
    487		netdev_err(dev, "DMAing conflict in ne_block_output."
    488			   "[DMAstat:%d][irqlock:%d][intr:%d]\n",
    489			   ei_status.dmaing, ei_status.irqlock, dev->irq);
    490	return;
    491    }
    492    ei_status.dmaing |= 0x01;
    493    /* We should already be in page 0, but to be safe... */
    494    outb(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD);
    495
    496    outb(ENISR_RDC, nic_base + NE_EN0_ISR);
    497
    498   /* Now the normal output. */
    499    outb(count & 0xff, nic_base + NE_EN0_RCNTLO);
    500    outb(count >> 8,   nic_base + NE_EN0_RCNTHI);
    501    outb(0x00, nic_base + NE_EN0_RSARLO);
    502    outb(start_page, nic_base + NE_EN0_RSARHI);
    503
    504    outb(E8390_RWRITE+E8390_START, nic_base + NE_CMD);
    505    if (ei_status.word16) {
    506        ptrs = (short*)buf;
    507        for (cnt = 0; cnt < count>>1; cnt++)
    508            outw(*ptrs++, NE_BASE+NE_DATAPORT);
    509    } else {
    510        ptrc = (char*)buf;
    511        for (cnt = 0; cnt < count; cnt++)
    512	    outb(*ptrc++, NE_BASE + NE_DATAPORT);
    513    }
    514
    515    dma_start = jiffies;
    516
    517    while ((inb(NE_BASE + NE_EN0_ISR) & ENISR_RDC) == 0)
    518	if (time_after(jiffies, dma_start + 2*HZ/100)) {	/* 20ms */
    519		netdev_warn(dev, "timeout waiting for Tx RDC.\n");
    520		apne_reset_8390(dev);
    521		NS8390_init(dev,1);
    522		break;
    523	}
    524
    525    outb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
    526    ei_status.dmaing &= ~0x01;
    527}
    528
    529static irqreturn_t apne_interrupt(int irq, void *dev_id)
    530{
    531    unsigned char pcmcia_intreq;
    532
    533    if (!(gayle.inten & GAYLE_IRQ_IRQ))
    534        return IRQ_NONE;
    535
    536    pcmcia_intreq = pcmcia_get_intreq();
    537
    538    if (!(pcmcia_intreq & GAYLE_IRQ_IRQ)) {
    539        pcmcia_ack_int(pcmcia_intreq);
    540        return IRQ_NONE;
    541    }
    542    if (apne_msg_enable & NETIF_MSG_INTR)
    543	pr_debug("pcmcia intreq = %x\n", pcmcia_intreq);
    544    pcmcia_disable_irq();			/* to get rid of the sti() within ei_interrupt */
    545    ei_interrupt(irq, dev_id);
    546    pcmcia_ack_int(pcmcia_get_intreq());
    547    pcmcia_enable_irq();
    548    return IRQ_HANDLED;
    549}
    550
    551static struct net_device *apne_dev;
    552
    553static int __init apne_module_init(void)
    554{
    555	apne_dev = apne_probe();
    556	return PTR_ERR_OR_ZERO(apne_dev);
    557}
    558
    559static void __exit apne_module_exit(void)
    560{
    561	unregister_netdev(apne_dev);
    562
    563	pcmcia_disable_irq();
    564
    565	free_irq(IRQ_AMIGA_PORTS, apne_dev);
    566
    567	pcmcia_reset();
    568
    569	release_region(IOBASE, 0x20);
    570
    571	free_netdev(apne_dev);
    572}
    573module_init(apne_module_init);
    574module_exit(apne_module_exit);
    575
    576static int init_pcmcia(void)
    577{
    578	u_char config;
    579#ifndef MANUAL_CONFIG
    580	u_char tuple[32];
    581	int offset_len;
    582#endif
    583	u_long offset;
    584
    585	pcmcia_reset();
    586	pcmcia_program_voltage(PCMCIA_0V);
    587	pcmcia_access_speed(PCMCIA_SPEED_250NS);
    588	pcmcia_write_enable();
    589
    590#ifdef MANUAL_CONFIG
    591	config = MANUAL_CONFIG;
    592#else
    593	/* get and write config byte to enable IO port */
    594
    595	if (pcmcia_copy_tuple(CISTPL_CFTABLE_ENTRY, tuple, 32) < 3)
    596		return 0;
    597
    598	config = tuple[2] & 0x3f;
    599#endif
    600#ifdef MANUAL_OFFSET
    601	offset = MANUAL_OFFSET;
    602#else
    603	if (pcmcia_copy_tuple(CISTPL_CONFIG, tuple, 32) < 6)
    604		return 0;
    605
    606	offset_len = (tuple[2] & 0x3) + 1;
    607	offset = 0;
    608	while(offset_len--) {
    609		offset = (offset << 8) | tuple[4+offset_len];
    610	}
    611#endif
    612
    613	out_8(GAYLE_ATTRIBUTE+offset, config);
    614
    615	return 1;
    616}
    617
    618MODULE_LICENSE("GPL");