!C99Shell v. 1.0 pre-release build #13!

Software: Apache/2.0.54 (Unix) mod_perl/1.99_09 Perl/v5.8.0 mod_ssl/2.0.54 OpenSSL/0.9.7l DAV/2 FrontPage/5.0.2.2635 PHP/4.4.0 mod_gzip/2.0.26.1a 

uname -a: Linux snow.he.net 4.4.276-v2-mono-1 #1 SMP Wed Jul 21 11:21:17 PDT 2021 i686 

uid=99(nobody) gid=98(nobody) groups=98(nobody) 

Safe-mode: OFF (not secure)

/usr/src/linux-2.4.18-xfs-1.1/drivers/parport/   drwxr-xr-x
Free 318.35 GB of 458.09 GB (69.5%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Feedback    Self remove    Logout    


Viewing file:     parport_pc.c (84.29 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/* Low-level parallel-port routines for 8255-based PC-style hardware.
 * 
 * Authors: Phil Blundell <Philip.Blundell@pobox.com>
 *          Tim Waugh <tim@cyberelk.demon.co.uk>
 *        Jose Renau <renau@acm.org>
 *          David Campbell <campbell@torque.net>
 *          Andrea Arcangeli
 *
 * based on work by Grant Guenther <grant@torque.net> and Phil Blundell.
 *
 * Cleaned up include files - Russell King <linux@arm.uk.linux.org>
 * DMA support - Bert De Jonghe <bert@sophis.be>
 * Many ECP bugs fixed.  Fred Barnes & Jamie Lokier, 1999
 * More PCI support now conditional on CONFIG_PCI, 03/2001, Paul G. 
 * Various hacks, Fred Barnes, 04/2001
 */

/* This driver should work with any hardware that is broadly compatible
 * with that in the IBM PC.  This applies to the majority of integrated
 * I/O chipsets that are commonly available.  The expected register
 * layout is:
 *
 *    base+0        data
 *    base+1        status
 *    base+2        control
 *
 * In addition, there are some optional registers:
 *
 *    base+3        EPP address
 *    base+4        EPP data
 *    base+0x400    ECP config A
 *    base+0x401    ECP config B
 *    base+0x402    ECP control
 *
 * All registers are 8 bits wide and read/write.  If your hardware differs
 * only in register addresses (eg because your registers are on 32-bit
 * word boundaries) then you can alter the constants in parport_pc.h to
 * accomodate this.
 *
 * Note that the ECP registers may not start at offset 0x400 for PCI cards,
 * but rather will start at port->base_hi.
 */

#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/sysctl.h>

#include <asm/io.h>
#include <asm/dma.h>
#include <asm/uaccess.h>

#include <linux/parport.h>
#include <linux/parport_pc.h>
#include <asm/parport.h>

#define PARPORT_PC_MAX_PORTS PARPORT_MAX

/* ECR modes */
#define ECR_SPP 00
#define ECR_PS2 01
#define ECR_PPF 02
#define ECR_ECP 03
#define ECR_EPP 04
#define ECR_VND 05
#define ECR_TST 06
#define ECR_CNF 07
#define ECR_MODE_MASK 0xe0
#define ECR_WRITE(p,v) frob_econtrol((p),0xff,(v))

#undef DEBUG

#ifdef DEBUG
#define DPRINTK  printk
#else
#define DPRINTK(stuff...)
#endif


#define NR_SUPERIOS 3
static struct superio_struct {    /* For Super-IO chips autodetection */
    int io;
    int irq;
    int dma;
} superios[NR_SUPERIOS] __devinitdata = { {0,},};

static int user_specified __devinitdata = 0;
#if defined(CONFIG_PARPORT_PC_FIFO) || defined(CONFIG_PARPORT_PC_SUPERIO)
static int verbose_probing;
#endif
static int registered_parport;

/* frob_control, but for ECR */
static void frob_econtrol (struct parport *pb, unsigned char m,
               unsigned char v)
{
    unsigned char ectr = 0;

    if (m != 0xff)
        ectr = inb (ECONTROL (pb));

    DPRINTK (KERN_DEBUG "frob_econtrol(%02x,%02x): %02x -> %02x\n",
        m, v, ectr, (ectr & ~m) ^ v);

    outb ((ectr & ~m) ^ v, ECONTROL (pb));
}

static void __inline__ frob_set_mode (struct parport *p, int mode)
{
    frob_econtrol (p, ECR_MODE_MASK, mode << 5);
}

#ifdef CONFIG_PARPORT_PC_FIFO
/* Safely change the mode bits in the ECR 
   Returns:
        0    : Success
       -EBUSY: Could not drain FIFO in some finite amount of time,
           mode not changed!
 */
static int change_mode(struct parport *p, int m)
{
    const struct parport_pc_private *priv = p->physport->private_data;
    unsigned char oecr;
    int mode;

    DPRINTK(KERN_INFO "parport change_mode ECP-ISA to mode 0x%02x\n",m);

    if (!priv->ecr) {
        printk (KERN_DEBUG "change_mode: but there's no ECR!\n");
        return 0;
    }

    /* Bits <7:5> contain the mode. */
    oecr = inb (ECONTROL (p));
    mode = (oecr >> 5) & 0x7;
    if (mode == m) return 0;

    if (mode >= 2 && !(priv->ctr & 0x20)) {
        /* This mode resets the FIFO, so we may
         * have to wait for it to drain first. */
        long expire = jiffies + p->physport->cad->timeout;
        int counter;
        switch (mode) {
        case ECR_PPF: /* Parallel Port FIFO mode */
        case ECR_ECP: /* ECP Parallel Port mode */
            /* Busy wait for 200us */
            for (counter = 0; counter < 40; counter++) {
                if (inb (ECONTROL (p)) & 0x01)
                    break;
                if (signal_pending (current)) break;
                udelay (5);
            }

            /* Poll slowly. */
            while (!(inb (ECONTROL (p)) & 0x01)) {
                if (time_after_eq (jiffies, expire))
                    /* The FIFO is stuck. */
                    return -EBUSY;
                __set_current_state (TASK_INTERRUPTIBLE);
                schedule_timeout ((HZ + 99) / 100);
                if (signal_pending (current))
                    break;
            }
        }
    }

    if (mode >= 2 && m >= 2) {
        /* We have to go through mode 001 */
        oecr &= ~(7 << 5);
        oecr |= ECR_PS2 << 5;
        ECR_WRITE (p, oecr);
    }

    /* Set the mode. */
    oecr &= ~(7 << 5);
    oecr |= m << 5;
    ECR_WRITE (p, oecr);
    return 0;
}

#ifdef CONFIG_PARPORT_1284
/* Find FIFO lossage; FIFO is reset */
static int get_fifo_residue (struct parport *p)
{
    int residue;
    int cnfga;
    const struct parport_pc_private *priv = p->physport->private_data;

    /* Adjust for the contents of the FIFO. */
    for (residue = priv->fifo_depth; ; residue--) {
        if (inb (ECONTROL (p)) & 0x2)
                /* Full up. */
            break;

        outb (0, FIFO (p));
    }

    printk (KERN_DEBUG "%s: %d PWords were left in FIFO\n", p->name,
        residue);

    /* Reset the FIFO. */
    frob_set_mode (p, ECR_PS2);

    /* Now change to config mode and clean up. FIXME */
    frob_set_mode (p, ECR_CNF);
    cnfga = inb (CONFIGA (p));
    printk (KERN_DEBUG "%s: cnfgA contains 0x%02x\n", p->name, cnfga);

    if (!(cnfga & (1<<2))) {
        printk (KERN_DEBUG "%s: Accounting for extra byte\n", p->name);
        residue++;
    }

    /* Don't care about partial PWords until support is added for
     * PWord != 1 byte. */

    /* Back to PS2 mode. */
    frob_set_mode (p, ECR_PS2);

    DPRINTK (KERN_DEBUG "*** get_fifo_residue: done residue collecting (ecr = 0x%2.2x)\n", inb (ECONTROL (p)));
    return residue;
}
#endif /* IEEE 1284 support */
#endif /* FIFO support */

/*
 * Clear TIMEOUT BIT in EPP MODE
 *
 * This is also used in SPP detection.
 */
static int clear_epp_timeout(struct parport *pb)
{
    unsigned char r;

    if (!(parport_pc_read_status(pb) & 0x01))
        return 1;

    /* To clear timeout some chips require double read */
    parport_pc_read_status(pb);
    r = parport_pc_read_status(pb);
    outb (r | 0x01, STATUS (pb)); /* Some reset by writing 1 */
    outb (r & 0xfe, STATUS (pb)); /* Others by writing 0 */
    r = parport_pc_read_status(pb);

    return !(r & 0x01);
}

/*
 * Access functions.
 *
 * Most of these aren't static because they may be used by the
 * parport_xxx_yyy macros.  extern __inline__ versions of several
 * of these are in parport_pc.h.
 */

static void parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
    parport_generic_irq(irq, (struct parport *) dev_id, regs);
}

void parport_pc_write_data(struct parport *p, unsigned char d)
{
    outb (d, DATA (p));
}

unsigned char parport_pc_read_data(struct parport *p)
{
    return inb (DATA (p));
}

void parport_pc_write_control(struct parport *p, unsigned char d)
{
    const unsigned char wm = (PARPORT_CONTROL_STROBE |
                  PARPORT_CONTROL_AUTOFD |
                  PARPORT_CONTROL_INIT |
                  PARPORT_CONTROL_SELECT);

    /* Take this out when drivers have adapted to the newer interface. */
    if (d & 0x20) {
        printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
            p->name, p->cad->name);
        parport_pc_data_reverse (p);
    }

    __parport_pc_frob_control (p, wm, d & wm);
}

unsigned char parport_pc_read_control(struct parport *p)
{
    const unsigned char wm = (PARPORT_CONTROL_STROBE |
                  PARPORT_CONTROL_AUTOFD |
                  PARPORT_CONTROL_INIT |
                  PARPORT_CONTROL_SELECT);
    const struct parport_pc_private *priv = p->physport->private_data;
    return priv->ctr & wm; /* Use soft copy */
}

unsigned char parport_pc_frob_control (struct parport *p, unsigned char mask,
                       unsigned char val)
{
    const unsigned char wm = (PARPORT_CONTROL_STROBE |
                  PARPORT_CONTROL_AUTOFD |
                  PARPORT_CONTROL_INIT |
                  PARPORT_CONTROL_SELECT);

    /* Take this out when drivers have adapted to the newer interface. */
    if (mask & 0x20) {
        printk (KERN_DEBUG "%s (%s): use data_%s for this!\n",
            p->name, p->cad->name,
            (val & 0x20) ? "reverse" : "forward");
        if (val & 0x20)
            parport_pc_data_reverse (p);
        else
            parport_pc_data_forward (p);
    }

    /* Restrict mask and val to control lines. */
    mask &= wm;
    val &= wm;

    return __parport_pc_frob_control (p, mask, val);
}

unsigned char parport_pc_read_status(struct parport *p)
{
    return inb (STATUS (p));
}

void parport_pc_disable_irq(struct parport *p)
{
    __parport_pc_frob_control (p, 0x10, 0);
}

void parport_pc_enable_irq(struct parport *p)
{
    if (p->irq != PARPORT_IRQ_NONE)
        __parport_pc_frob_control (p, 0x10, 0x10);
}

void parport_pc_data_forward (struct parport *p)
{
    __parport_pc_frob_control (p, 0x20, 0);
}

void parport_pc_data_reverse (struct parport *p)
{
    __parport_pc_frob_control (p, 0x20, 0x20);
}

void parport_pc_init_state(struct pardevice *dev, struct parport_state *s)
{
    s->u.pc.ctr = 0xc;
    if (dev->irq_func &&
        dev->port->irq != PARPORT_IRQ_NONE)
        /* Set ackIntEn */
        s->u.pc.ctr |= 0x10;

    s->u.pc.ecr = 0x34; /* NetMos chip can cause problems 0x24;
                 * D.Gruszka VScom */
}

void parport_pc_save_state(struct parport *p, struct parport_state *s)
{
    const struct parport_pc_private *priv = p->physport->private_data;
    s->u.pc.ctr = priv->ctr;
    if (priv->ecr)
        s->u.pc.ecr = inb (ECONTROL (p));
}

void parport_pc_restore_state(struct parport *p, struct parport_state *s)
{
    struct parport_pc_private *priv = p->physport->private_data;
    register unsigned char c = s->u.pc.ctr & priv->ctr_writable;
    outb (c, CONTROL (p));
    priv->ctr = c;
    if (priv->ecr)
        ECR_WRITE (p, s->u.pc.ecr);
}

#ifdef CONFIG_PARPORT_1284
static size_t parport_pc_epp_read_data (struct parport *port, void *buf,
                    size_t length, int flags)
{
    size_t got = 0;

    if (flags & PARPORT_W91284PIC) {
        unsigned char status;
        size_t left = length;

        /* use knowledge about data lines..:
         *  nFault is 0 if there is at least 1 byte in the Warp's FIFO
         *  pError is 1 if there are 16 bytes in the Warp's FIFO
         */
        status = inb (STATUS (port));

        while (!(status & 0x08) && (got < length)) {
            if ((left >= 16) && (status & 0x20) && !(status & 0x08)) {
                /* can grab 16 bytes from warp fifo */
                if (!((long)buf & 0x03)) {
                    insl (EPPDATA (port), buf, 4);
                } else {
                    insb (EPPDATA (port), buf, 16);
                }
                buf += 16;
                got += 16;
                left -= 16;
            } else {
                /* grab single byte from the warp fifo */
                *((char *)buf)++ = inb (EPPDATA (port));
                got++;
                left--;
            }
            status = inb (STATUS (port));
            if (status & 0x01) {
                /* EPP timeout should never occur... */
                printk (KERN_DEBUG "%s: EPP timeout occured while talking to "
                    "w91284pic (should not have done)\n", port->name);
                clear_epp_timeout (port);
            }
        }
        return got;
    }
    if ((flags & PARPORT_EPP_FAST) && (length > 1)) {
        if (!(((long)buf | length) & 0x03)) {
            insl (EPPDATA (port), buf, (length >> 2));
        } else {
            insb (EPPDATA (port), buf, length);
        }
        if (inb (STATUS (port)) & 0x01) {
            clear_epp_timeout (port);
            return -EIO;
        }
        return length;
    }
    for (; got < length; got++) {
        *((char*)buf)++ = inb (EPPDATA(port));
        if (inb (STATUS (port)) & 0x01) {
            /* EPP timeout */
            clear_epp_timeout (port);
            break;
        }
    }

    return got;
}

static size_t parport_pc_epp_write_data (struct parport *port, const void *buf,
                     size_t length, int flags)
{
    size_t written = 0;

    if ((flags & PARPORT_EPP_FAST) && (length > 1)) {
        if (!(((long)buf | length) & 0x03)) {
            outsl (EPPDATA (port), buf, (length >> 2));
        } else {
            outsb (EPPDATA (port), buf, length);
        }
        if (inb (STATUS (port)) & 0x01) {
            clear_epp_timeout (port);
            return -EIO;
        }
        return length;
    }
    for (; written < length; written++) {
        outb (*((char*)buf)++, EPPDATA(port));
        if (inb (STATUS(port)) & 0x01) {
            clear_epp_timeout (port);
            break;
        }
    }

    return written;
}

static size_t parport_pc_epp_read_addr (struct parport *port, void *buf,
                    size_t length, int flags)
{
    size_t got = 0;

    if ((flags & PARPORT_EPP_FAST) && (length > 1)) {
        insb (EPPADDR (port), buf, length);
        if (inb (STATUS (port)) & 0x01) {
            clear_epp_timeout (port);
            return -EIO;
        }
        return length;
    }
    for (; got < length; got++) {
        *((char*)buf)++ = inb (EPPADDR (port));
        if (inb (STATUS (port)) & 0x01) {
            clear_epp_timeout (port);
            break;
        }
    }

    return got;
}

static size_t parport_pc_epp_write_addr (struct parport *port,
                     const void *buf, size_t length,
                     int flags)
{
    size_t written = 0;

    if ((flags & PARPORT_EPP_FAST) && (length > 1)) {
        outsb (EPPADDR (port), buf, length);
        if (inb (STATUS (port)) & 0x01) {
            clear_epp_timeout (port);
            return -EIO;
        }
        return length;
    }
    for (; written < length; written++) {
        outb (*((char*)buf)++, EPPADDR (port));
        if (inb (STATUS (port)) & 0x01) {
            clear_epp_timeout (port);
            break;
        }
    }

    return written;
}

static size_t parport_pc_ecpepp_read_data (struct parport *port, void *buf,
                       size_t length, int flags)
{
    size_t got;

    frob_set_mode (port, ECR_EPP);
    parport_pc_data_reverse (port);
    parport_pc_write_control (port, 0x4);
    got = parport_pc_epp_read_data (port, buf, length, flags);
    frob_set_mode (port, ECR_PS2);

    return got;
}

static size_t parport_pc_ecpepp_write_data (struct parport *port,
                        const void *buf, size_t length,
                        int flags)
{
    size_t written;

    frob_set_mode (port, ECR_EPP);
    parport_pc_write_control (port, 0x4);
    parport_pc_data_forward (port);
    written = parport_pc_epp_write_data (port, buf, length, flags);
    frob_set_mode (port, ECR_PS2);

    return written;
}

static size_t parport_pc_ecpepp_read_addr (struct parport *port, void *buf,
                       size_t length, int flags)
{
    size_t got;

    frob_set_mode (port, ECR_EPP);
    parport_pc_data_reverse (port);
    parport_pc_write_control (port, 0x4);
    got = parport_pc_epp_read_addr (port, buf, length, flags);
    frob_set_mode (port, ECR_PS2);

    return got;
}

static size_t parport_pc_ecpepp_write_addr (struct parport *port,
                        const void *buf, size_t length,
                        int flags)
{
    size_t written;

    frob_set_mode (port, ECR_EPP);
    parport_pc_write_control (port, 0x4);
    parport_pc_data_forward (port);
    written = parport_pc_epp_write_addr (port, buf, length, flags);
    frob_set_mode (port, ECR_PS2);

    return written;
}
#endif /* IEEE 1284 support */

#ifdef CONFIG_PARPORT_PC_FIFO
static size_t parport_pc_fifo_write_block_pio (struct parport *port,
                           const void *buf, size_t length)
{
    int ret = 0;
    const unsigned char *bufp = buf;
    size_t left = length;
    long expire = jiffies + port->physport->cad->timeout;
    const int fifo = FIFO (port);
    int poll_for = 8; /* 80 usecs */
    const struct parport_pc_private *priv = port->physport->private_data;
    const int fifo_depth = priv->fifo_depth;

    port = port->physport;

    /* We don't want to be interrupted every character. */
    parport_pc_disable_irq (port);
    /* set nErrIntrEn and serviceIntr */
    frob_econtrol (port, (1<<4) | (1<<2), (1<<4) | (1<<2));

    /* Forward mode. */
    parport_pc_data_forward (port); /* Must be in PS2 mode */

    while (left) {
        unsigned char byte;
        unsigned char ecrval = inb (ECONTROL (port));
        int i = 0;

        if (current->need_resched && time_before (jiffies, expire))
            /* Can't yield the port. */
            schedule ();

        /* Anyone else waiting for the port? */
        if (port->waithead) {
            printk (KERN_DEBUG "Somebody wants the port\n");
            break;
        }

        if (ecrval & 0x02) {
            /* FIFO is full. Wait for interrupt. */

            /* Clear serviceIntr */
            ECR_WRITE (port, ecrval & ~(1<<2));
        false_alarm:
            ret = parport_wait_event (port, HZ);
            if (ret < 0) break;
            ret = 0;
            if (!time_before (jiffies, expire)) {
                /* Timed out. */
                printk (KERN_DEBUG "FIFO write timed out\n");
                break;
            }
            ecrval = inb (ECONTROL (port));
            if (!(ecrval & (1<<2))) {
                if (current->need_resched &&
                    time_before (jiffies, expire))
                    schedule ();

                goto false_alarm;
            }

            continue;
        }

        /* Can't fail now. */
        expire = jiffies + port->cad->timeout;

    poll:
        if (signal_pending (current))
            break;

        if (ecrval & 0x01) {
            /* FIFO is empty. Blast it full. */
            const int n = left < fifo_depth ? left : fifo_depth;
            outsb (fifo, bufp, n);
            bufp += n;
            left -= n;

            /* Adjust the poll time. */
            if (i < (poll_for - 2)) poll_for--;
            continue;
        } else if (i++ < poll_for) {
            udelay (10);
            ecrval = inb (ECONTROL (port));
            goto poll;
        }

        /* Half-full (call me an optimist) */
        byte = *bufp++;
        outb (byte, fifo);
        left--;
        }

dump_parport_state ("leave fifo_write_block_pio", port);
    return length - left;
}

static size_t parport_pc_fifo_write_block_dma (struct parport *port,
                           const void *buf, size_t length)
{
    int ret = 0;
    unsigned long dmaflag;
    size_t left = length;
    const struct parport_pc_private *priv = port->physport->private_data;
    dma_addr_t dma_addr, dma_handle;
    size_t maxlen = 0x10000; /* max 64k per DMA transfer */
    unsigned long start = (unsigned long) buf;
    unsigned long end = (unsigned long) buf + length - 1;

dump_parport_state ("enter fifo_write_block_dma", port);
    if (end < MAX_DMA_ADDRESS) {
        /* If it would cross a 64k boundary, cap it at the end. */
        if ((start ^ end) & ~0xffffUL)
            maxlen = 0x10000 - (start & 0xffff);

        dma_addr = dma_handle = pci_map_single(priv->dev, (void *)buf, length,
                               PCI_DMA_TODEVICE);
        } else {
        /* above 16 MB we use a bounce buffer as ISA-DMA is not possible */
        maxlen   = PAGE_SIZE;          /* sizeof(priv->dma_buf) */
        dma_addr = priv->dma_handle;
        dma_handle = 0;
    }

    port = port->physport;

    /* We don't want to be interrupted every character. */
    parport_pc_disable_irq (port);
    /* set nErrIntrEn and serviceIntr */
    frob_econtrol (port, (1<<4) | (1<<2), (1<<4) | (1<<2));

    /* Forward mode. */
    parport_pc_data_forward (port); /* Must be in PS2 mode */

    while (left) {
        long expire = jiffies + port->physport->cad->timeout;

        size_t count = left;

        if (count > maxlen)
            count = maxlen;

        if (!dma_handle)   /* bounce buffer ! */
            memcpy(priv->dma_buf, buf, count);

        dmaflag = claim_dma_lock();
        disable_dma(port->dma);
        clear_dma_ff(port->dma);
        set_dma_mode(port->dma, DMA_MODE_WRITE);
        set_dma_addr(port->dma, dma_addr);
        set_dma_count(port->dma, count);

        /* Set DMA mode */
        frob_econtrol (port, 1<<3, 1<<3);

        /* Clear serviceIntr */
        frob_econtrol (port, 1<<2, 0);

        enable_dma(port->dma);
        release_dma_lock(dmaflag);

        /* assume DMA will be successful */
        left -= count;
        buf  += count;
        if (dma_handle) dma_addr += count;

        /* Wait for interrupt. */
    false_alarm:
        ret = parport_wait_event (port, HZ);
        if (ret < 0) break;
        ret = 0;
        if (!time_before (jiffies, expire)) {
            /* Timed out. */
            printk (KERN_DEBUG "DMA write timed out\n");
            break;
        }
        /* Is serviceIntr set? */
        if (!(inb (ECONTROL (port)) & (1<<2))) {
            if (current->need_resched)
                schedule ();

            goto false_alarm;
        }

        dmaflag = claim_dma_lock();
        disable_dma(port->dma);
        clear_dma_ff(port->dma);
        count = get_dma_residue(port->dma);
        release_dma_lock(dmaflag);

        if (current->need_resched)
            /* Can't yield the port. */
            schedule ();

        /* Anyone else waiting for the port? */
        if (port->waithead) {
            printk (KERN_DEBUG "Somebody wants the port\n");
            break;
        }

        /* update for possible DMA residue ! */
        buf  -= count;
        left += count;
        if (dma_handle) dma_addr -= count;
    }

    /* Maybe got here through break, so adjust for DMA residue! */
    dmaflag = claim_dma_lock();
    disable_dma(port->dma);
    clear_dma_ff(port->dma);
    left += get_dma_residue(port->dma);
    release_dma_lock(dmaflag);

    /* Turn off DMA mode */
    frob_econtrol (port, 1<<3, 0);
    
    if (dma_handle)
        pci_unmap_single(priv->dev, dma_handle, length, PCI_DMA_TODEVICE);

dump_parport_state ("leave fifo_write_block_dma", port);
    return length - left;
}

/* Parallel Port FIFO mode (ECP chipsets) */
size_t parport_pc_compat_write_block_pio (struct parport *port,
                      const void *buf, size_t length,
                      int flags)
{
    size_t written;
    int r;
    long int expire;
    const struct parport_pc_private *priv = port->physport->private_data;

    /* Special case: a timeout of zero means we cannot call schedule(). */
    if (!port->physport->cad->timeout)
        return parport_ieee1284_write_compat (port, buf,
                              length, flags);

    /* Set up parallel port FIFO mode.*/
    parport_pc_data_forward (port); /* Must be in PS2 mode */
    parport_pc_frob_control (port, PARPORT_CONTROL_STROBE, 0);
    r = change_mode (port, ECR_PPF); /* Parallel port FIFO */
    if (r)  printk (KERN_DEBUG "%s: Warning change_mode ECR_PPF failed\n", port->name);

    port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;

    /* Write the data to the FIFO. */
    if (port->dma != PARPORT_DMA_NONE)
        written = parport_pc_fifo_write_block_dma (port, buf, length);
    else
        written = parport_pc_fifo_write_block_pio (port, buf, length);

    /* Finish up. */
    /* For some hardware we don't want to touch the mode until
     * the FIFO is empty, so allow 4 seconds for each position
     * in the fifo.
     */
        expire = jiffies + (priv->fifo_depth * HZ * 4);
    do {
        /* Wait for the FIFO to empty */
        r = change_mode (port, ECR_PS2);
        if (r != -EBUSY) {
            break;
        }
    } while (time_before (jiffies, expire));
    if (r == -EBUSY) {

        printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name);

        /* Prevent further data transfer. */
        frob_set_mode (port, ECR_TST);

        /* Adjust for the contents of the FIFO. */
        for (written -= priv->fifo_depth; ; written++) {
            if (inb (ECONTROL (port)) & 0x2) {
                /* Full up. */
                break;
            }
            outb (0, FIFO (port));
        }

        /* Reset the FIFO and return to PS2 mode. */
        frob_set_mode (port, ECR_PS2);
    }

    r = parport_wait_peripheral (port,
                     PARPORT_STATUS_BUSY,
                     PARPORT_STATUS_BUSY);
    if (r)
        printk (KERN_DEBUG
            "%s: BUSY timeout (%d) in compat_write_block_pio\n", 
            port->name, r);

    port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;

    return written;
}

/* ECP */
#ifdef CONFIG_PARPORT_1284
size_t parport_pc_ecp_write_block_pio (struct parport *port,
                       const void *buf, size_t length,
                       int flags)
{
    size_t written;
    int r;
    long int expire;
    const struct parport_pc_private *priv = port->physport->private_data;

    /* Special case: a timeout of zero means we cannot call schedule(). */
    if (!port->physport->cad->timeout)
        return parport_ieee1284_ecp_write_data (port, buf,
                            length, flags);

    /* Switch to forward mode if necessary. */
    if (port->physport->ieee1284.phase != IEEE1284_PH_FWD_IDLE) {
        /* Event 47: Set nInit high. */
        parport_frob_control (port,
                      PARPORT_CONTROL_INIT
                      | PARPORT_CONTROL_AUTOFD,
                      PARPORT_CONTROL_INIT
                      | PARPORT_CONTROL_AUTOFD);

        /* Event 49: PError goes high. */
        r = parport_wait_peripheral (port,
                         PARPORT_STATUS_PAPEROUT,
                         PARPORT_STATUS_PAPEROUT);
        if (r) {
            printk (KERN_DEBUG "%s: PError timeout (%d) "
                "in ecp_write_block_pio\n", port->name, r);
        }
    }

    /* Set up ECP parallel port mode.*/
    parport_pc_data_forward (port); /* Must be in PS2 mode */
    parport_pc_frob_control (port,
                 PARPORT_CONTROL_STROBE |
                 PARPORT_CONTROL_AUTOFD,
                 0);
    r = change_mode (port, ECR_ECP); /* ECP FIFO */
    if (r) printk (KERN_DEBUG "%s: Warning change_mode ECR_ECP failed\n", port->name);
    port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;

    /* Write the data to the FIFO. */
    if (port->dma != PARPORT_DMA_NONE)
        written = parport_pc_fifo_write_block_dma (port, buf, length);
    else
        written = parport_pc_fifo_write_block_pio (port, buf, length);

    /* Finish up. */
    /* For some hardware we don't want to touch the mode until
     * the FIFO is empty, so allow 4 seconds for each position
     * in the fifo.
     */
    expire = jiffies + (priv->fifo_depth * (HZ * 4));
    do {
        /* Wait for the FIFO to empty */
        r = change_mode (port, ECR_PS2);
        if (r != -EBUSY) {
            break;
        }
    } while (time_before (jiffies, expire));
    if (r == -EBUSY) {

        printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name);

        /* Prevent further data transfer. */
        frob_set_mode (port, ECR_TST);

        /* Adjust for the contents of the FIFO. */
        for (written -= priv->fifo_depth; ; written++) {
            if (inb (ECONTROL (port)) & 0x2) {
                /* Full up. */
                break;
            }
            outb (0, FIFO (port));
        }

        /* Reset the FIFO and return to PS2 mode. */
        frob_set_mode (port, ECR_PS2);

        /* Host transfer recovery. */
        parport_pc_data_reverse (port); /* Must be in PS2 mode */
        udelay (5);
        parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
        r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
        if (r)
            printk (KERN_DEBUG "%s: PE,1 timeout (%d) "
                "in ecp_write_block_pio\n", port->name, r);

        parport_frob_control (port,
                      PARPORT_CONTROL_INIT,
                      PARPORT_CONTROL_INIT);
        r = parport_wait_peripheral (port,
                         PARPORT_STATUS_PAPEROUT,
                         PARPORT_STATUS_PAPEROUT);
                if (r)
                        printk (KERN_DEBUG "%s: PE,2 timeout (%d) "
                "in ecp_write_block_pio\n", port->name, r);
    }

    r = parport_wait_peripheral (port,
                     PARPORT_STATUS_BUSY, 
                     PARPORT_STATUS_BUSY);
    if(r)
        printk (KERN_DEBUG
            "%s: BUSY timeout (%d) in ecp_write_block_pio\n",
            port->name, r);

    port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;

    return written;
}

size_t parport_pc_ecp_read_block_pio (struct parport *port,
                      void *buf, size_t length, int flags)
{
    size_t left = length;
    size_t fifofull;
    int r;
    const int fifo = FIFO(port);
    const struct parport_pc_private *priv = port->physport->private_data;
    const int fifo_depth = priv->fifo_depth;
    char *bufp = buf;

    port = port->physport;
DPRINTK (KERN_DEBUG "parport_pc: parport_pc_ecp_read_block_pio\n");
dump_parport_state ("enter fcn", port);

    /* Special case: a timeout of zero means we cannot call schedule(). */
    if (!port->cad->timeout)
        return parport_ieee1284_ecp_read_data (port, buf,
                               length, flags);

    if (port->ieee1284.mode == IEEE1284_MODE_ECPRLE) {
        /* If the peripheral is allowed to send RLE compressed
         * data, it is possible for a byte to expand to 128
         * bytes in the FIFO. */
        fifofull = 128;
    } else {
        fifofull = fifo_depth;
    }

    /* If the caller wants less than a full FIFO's worth of data,
     * go through software emulation.  Otherwise we may have to throw
     * away data. */
    if (length < fifofull)
        return parport_ieee1284_ecp_read_data (port, buf,
                               length, flags);

    if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE) {
        /* change to reverse-idle phase (must be in forward-idle) */

        /* Event 38: Set nAutoFd low (also make sure nStrobe is high) */
        parport_frob_control (port,
                      PARPORT_CONTROL_AUTOFD
                      | PARPORT_CONTROL_STROBE,
                      PARPORT_CONTROL_AUTOFD);
        parport_pc_data_reverse (port); /* Must be in PS2 mode */
        udelay (5);
        /* Event 39: Set nInit low to initiate bus reversal */
        parport_frob_control (port,
                      PARPORT_CONTROL_INIT,
                      0);
        /* Event 40: Wait for  nAckReverse (PError) to go low */
        r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
                if (r) {
                        printk (KERN_DEBUG "%s: PE timeout Event 40 (%d) "
                "in ecp_read_block_pio\n", port->name, r);
            return 0;
        }
    }

    /* Set up ECP FIFO mode.*/
/*    parport_pc_frob_control (port,
                 PARPORT_CONTROL_STROBE |
                 PARPORT_CONTROL_AUTOFD,
                 PARPORT_CONTROL_AUTOFD); */
    r = change_mode (port, ECR_ECP); /* ECP FIFO */
    if (r) printk (KERN_DEBUG "%s: Warning change_mode ECR_ECP failed\n", port->name);

    port->ieee1284.phase = IEEE1284_PH_REV_DATA;

    /* the first byte must be collected manually */
dump_parport_state ("pre 43", port);
    /* Event 43: Wait for nAck to go low */
    r = parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0);
    if (r) {
        /* timed out while reading -- no data */
        printk (KERN_DEBUG "PIO read timed out (initial byte)\n");
        goto out_no_data;
    }
    /* read byte */
    *bufp++ = inb (DATA (port));
    left--;
dump_parport_state ("43-44", port);
    /* Event 44: nAutoFd (HostAck) goes high to acknowledge */
    parport_pc_frob_control (port,
                 PARPORT_CONTROL_AUTOFD,
                 0);
dump_parport_state ("pre 45", port);
    /* Event 45: Wait for nAck to go high */
/*    r = parport_wait_peripheral (port, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK); */
dump_parport_state ("post 45", port);
r = 0;
    if (r) {
        /* timed out while waiting for peripheral to respond to ack */
        printk (KERN_DEBUG "ECP PIO read timed out (waiting for nAck)\n");

        /* keep hold of the byte we've got already */
        goto out_no_data;
    }
    /* Event 46: nAutoFd (HostAck) goes low to accept more data */
    parport_pc_frob_control (port,
                 PARPORT_CONTROL_AUTOFD,
                 PARPORT_CONTROL_AUTOFD);


dump_parport_state ("rev idle", port);
    /* Do the transfer. */
    while (left > fifofull) {
        int ret;
        long int expire = jiffies + port->cad->timeout;
        unsigned char ecrval = inb (ECONTROL (port));

        if (current->need_resched && time_before (jiffies, expire))
            /* Can't yield the port. */
            schedule ();

        /* At this point, the FIFO may already be full. In
                 * that case ECP is already holding back the
                 * peripheral (assuming proper design) with a delayed
                 * handshake.  Work fast to avoid a peripheral
                 * timeout.  */

        if (ecrval & 0x01) {
            /* FIFO is empty. Wait for interrupt. */
dump_parport_state ("FIFO empty", port);

            /* Anyone else waiting for the port? */
            if (port->waithead) {
                printk (KERN_DEBUG "Somebody wants the port\n");
                break;
            }

            /* Clear serviceIntr */
            ECR_WRITE (port, ecrval & ~(1<<2));
        false_alarm:
dump_parport_state ("waiting", port);
            ret = parport_wait_event (port, HZ);
DPRINTK (KERN_DEBUG "parport_wait_event returned %d\n", ret);
            if (ret < 0)
                break;
            ret = 0;
            if (!time_before (jiffies, expire)) {
                /* Timed out. */
dump_parport_state ("timeout", port);
                printk (KERN_DEBUG "PIO read timed out\n");
                break;
            }
            ecrval = inb (ECONTROL (port));
            if (!(ecrval & (1<<2))) {
                if (current->need_resched &&
                    time_before (jiffies, expire)) {
                    schedule ();
                }
                goto false_alarm;
            }

            /* Depending on how the FIFO threshold was
                         * set, how long interrupt service took, and
                         * how fast the peripheral is, we might be
                         * lucky and have a just filled FIFO. */
            continue;
        }

        if (ecrval & 0x02) {
            /* FIFO is full. */
dump_parport_state ("FIFO full", port);
            insb (fifo, bufp, fifo_depth);
            bufp += fifo_depth;
            left -= fifo_depth;
            continue;
        }

DPRINTK (KERN_DEBUG "*** ecp_read_block_pio: reading one byte from the FIFO\n");

        /* FIFO not filled.  We will cycle this loop for a while
                 * and either the peripheral will fill it faster,
                 * tripping a fast empty with insb, or we empty it. */
        *bufp++ = inb (fifo);
        left--;
    }

    /* scoop up anything left in the FIFO */
    while (left && !(inb (ECONTROL (port) & 0x01))) {
        *bufp++ = inb (fifo);
        left--;
    }

    port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
dump_parport_state ("rev idle2", port);

out_no_data:

    /* Go to forward idle mode to shut the peripheral up (event 47). */
    parport_frob_control (port, PARPORT_CONTROL_INIT, PARPORT_CONTROL_INIT);

    /* event 49: PError goes high */
    r = parport_wait_peripheral (port,
                     PARPORT_STATUS_PAPEROUT,
                     PARPORT_STATUS_PAPEROUT);
    if (r) {
        printk (KERN_DEBUG
            "%s: PE timeout FWDIDLE (%d) in ecp_read_block_pio\n",
            port->name, r);
    }

    port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;

    /* Finish up. */
    {
        int lost = get_fifo_residue (port);
        if (lost)
            /* Shouldn't happen with compliant peripherals. */
            printk (KERN_DEBUG "%s: DATA LOSS (%d bytes)!\n",
                port->name, lost);
    }

dump_parport_state ("fwd idle", port);
    return length - left;
}

#endif /* IEEE 1284 support */
#endif /* Allowed to use FIFO/DMA */


/*
 *    ******************************************
 *    INITIALISATION AND MODULE STUFF BELOW HERE
 *    ******************************************
 */


void parport_pc_inc_use_count(void)
{
#ifdef MODULE
    MOD_INC_USE_COUNT;
#endif
}

void parport_pc_dec_use_count(void)
{
#ifdef MODULE
    MOD_DEC_USE_COUNT;
#endif
}

struct parport_operations parport_pc_ops = 
{
    parport_pc_write_data,
    parport_pc_read_data,

    parport_pc_write_control,
    parport_pc_read_control,
    parport_pc_frob_control,

    parport_pc_read_status,

    parport_pc_enable_irq,
    parport_pc_disable_irq,

    parport_pc_data_forward,
    parport_pc_data_reverse,

    parport_pc_init_state,
    parport_pc_save_state,
    parport_pc_restore_state,

    parport_pc_inc_use_count,
    parport_pc_dec_use_count,

    parport_ieee1284_epp_write_data,
    parport_ieee1284_epp_read_data,
    parport_ieee1284_epp_write_addr,
    parport_ieee1284_epp_read_addr,

    parport_ieee1284_ecp_write_data,
    parport_ieee1284_ecp_read_data,
    parport_ieee1284_ecp_write_addr,

    parport_ieee1284_write_compat,
    parport_ieee1284_read_nibble,
    parport_ieee1284_read_byte,
};

#ifdef CONFIG_PARPORT_PC_SUPERIO
/* Super-IO chipset detection, Winbond, SMSC */
static void __devinit show_parconfig_smsc37c669(int io, int key)
{
    int cr1,cr4,cra,cr23,cr26,cr27,i=0;
    static const char *modes[]={ "SPP and Bidirectional (PS/2)",    
                     "EPP and SPP",
                     "ECP",
                     "ECP and EPP" };

    outb(key,io);
    outb(key,io);
    outb(1,io);
    cr1=inb(io+1);
    outb(4,io);
    cr4=inb(io+1);
    outb(0x0a,io);
    cra=inb(io+1);
    outb(0x23,io);
    cr23=inb(io+1);
    outb(0x26,io);
    cr26=inb(io+1);
    outb(0x27,io);
    cr27=inb(io+1);
    outb(0xaa,io);

    if (verbose_probing) {
        printk (KERN_INFO "SMSC 37c669 LPT Config: cr_1=0x%02x, 4=0x%02x, "
            "A=0x%2x, 23=0x%02x, 26=0x%02x, 27=0x%02x\n",
            cr1,cr4,cra,cr23,cr26,cr27);
        
        /* The documentation calls DMA and IRQ-Lines by letters, so
           the board maker can/will wire them
           appropriately/randomly...  G=reserved H=IDE-irq, */
        printk (KERN_INFO "SMSC LPT Config: io=0x%04x, irq=%c, dma=%c, "
            "fifo threshold=%d\n", cr23*4,
            (cr27 &0x0f) ? 'A'-1+(cr27 &0x0f): '-',
            (cr26 &0x0f) ? 'A'-1+(cr26 &0x0f): '-', cra & 0x0f);
        printk(KERN_INFO "SMSC LPT Config: enabled=%s power=%s\n",
               (cr23*4 >=0x100) ?"yes":"no", (cr1 & 4) ? "yes" : "no");
        printk(KERN_INFO "SMSC LPT Config: Port mode=%s, EPP version =%s\n",
               (cr1 & 0x08 ) ? "Standard mode only (SPP)" : modes[cr4 & 0x03], 
               (cr4 & 0x40) ? "1.7" : "1.9");
    }
        
    /* Heuristics !  BIOS setup for this mainboard device limits
       the choices to standard settings, i.e. io-address and IRQ
       are related, however DMA can be 1 or 3, assume DMA_A=DMA1,
       DMA_C=DMA3 (this is true e.g. for TYAN 1564D Tomcat IV) */
    if(cr23*4 >=0x100) { /* if active */
        while((superios[i].io!= 0) && (i<NR_SUPERIOS))
            i++;
        if(i==NR_SUPERIOS)
            printk(KERN_INFO "Super-IO: too many chips!\n");
        else {
            int d;
            switch (cr23*4) {
                case 0x3bc:
                    superios[i].io = 0x3bc;
                    superios[i].irq = 7;
                    break;
                case 0x378:
                    superios[i].io = 0x378;
                    superios[i].irq = 7;
                    break;
                case 0x278:
                    superios[i].io = 0x278;
                    superios[i].irq = 5;
            }
            d=(cr26 &0x0f);
            if((d==1) || (d==3)) 
                superios[i].dma= d;
            else
                superios[i].dma= PARPORT_DMA_NONE;
        }
     }
}


static void __devinit show_parconfig_winbond(int io, int key)
{
    int cr30,cr60,cr61,cr70,cr74,crf0,i=0;
    static const char *modes[] = {
        "Standard (SPP) and Bidirectional(PS/2)", /* 0 */
        "EPP-1.9 and SPP",
        "ECP",
        "ECP and EPP-1.9",
        "Standard (SPP)",
        "EPP-1.7 and SPP",        /* 5 */
        "undefined!",
        "ECP and EPP-1.7" };
    static char *irqtypes[] = { "pulsed low, high-Z", "follows nACK" };
        
    /* The registers are called compatible-PnP because the
           register layout is modelled after ISA-PnP, the access
           method is just another ... */
    outb(key,io);
    outb(key,io);
    outb(0x07,io);   /* Register 7: Select Logical Device */
    outb(0x01,io+1); /* LD1 is Parallel Port */
    outb(0x30,io);
    cr30=inb(io+1);
    outb(0x60,io);
    cr60=inb(io+1);
    outb(0x61,io);
    cr61=inb(io+1);
    outb(0x70,io);
    cr70=inb(io+1);
    outb(0x74,io);
    cr74=inb(io+1);
    outb(0xf0,io);
    crf0=inb(io+1);
    outb(0xaa,io);

    if (verbose_probing) {
        printk(KERN_INFO "Winbond LPT Config: cr_30=%02x 60,61=%02x%02x "
               "70=%02x 74=%02x, f0=%02x\n", cr30,cr60,cr61,cr70,cr74,crf0);
        printk(KERN_INFO "Winbond LPT Config: active=%s, io=0x%02x%02x irq=%d, ", 
               (cr30 & 0x01) ? "yes":"no", cr60,cr61,cr70&0x0f );
        if ((cr74 & 0x07) > 3)
            printk("dma=none\n");
        else
            printk("dma=%d\n",cr74 & 0x07);
        printk(KERN_INFO "Winbond LPT Config: irqtype=%s, ECP fifo threshold=%d\n",
               irqtypes[crf0>>7], (crf0>>3)&0x0f);
        printk(KERN_INFO "Winbond LPT Config: Port mode=%s\n", modes[crf0 & 0x07]);
    }

    if(cr30 & 0x01) { /* the settings can be interrogated later ... */
        while((superios[i].io!= 0) && (i<NR_SUPERIOS))
            i++;
        if(i==NR_SUPERIOS) 
            printk(KERN_INFO "Super-IO: too many chips!\n");
        else {
            superios[i].io = (cr60<<8)|cr61;
            superios[i].irq = cr70&0x0f;
            superios[i].dma = (((cr74 & 0x07) > 3) ?
                       PARPORT_DMA_NONE : (cr74 & 0x07));
        }
    }
}

static void __devinit decode_winbond(int efer, int key, int devid, int devrev, int oldid)
{
    const char *type = "unknown";
    int id,progif=2;

    if (devid == devrev)
        /* simple heuristics, we happened to read some
                   non-winbond register */
        return;

    id=(devid<<8) | devrev;

    /* Values are from public data sheets pdf files, I can just
           confirm 83977TF is correct :-) */
    if      (id == 0x9771) type="83977F/AF";
    else if (id == 0x9773) type="83977TF / SMSC 97w33x/97w34x";
    else if (id == 0x9774) type="83977ATF";
    else if ((id & ~0x0f) == 0x5270) type="83977CTF / SMSC 97w36x";
    else if ((id & ~0x0f) == 0x52f0) type="83977EF / SMSC 97w35x";
    else if ((id & ~0x0f) == 0x5210) type="83627";
    else if ((id & ~0x0f) == 0x6010) type="83697HF";
    else if ((oldid &0x0f ) == 0x0a) { type="83877F"; progif=1;}
    else if ((oldid &0x0f ) == 0x0b) { type="83877AF"; progif=1;}
    else if ((oldid &0x0f ) == 0x0c) { type="83877TF"; progif=1;}
    else if ((oldid &0x0f ) == 0x0d) { type="83877ATF"; progif=1;}
    else progif=0;

    if (verbose_probing)
        printk(KERN_INFO "Winbond chip at EFER=0x%x key=0x%02x "
               "devid=%02x devrev=%02x oldid=%02x type=%s\n", 
               efer, key, devid, devrev, oldid, type);

    if (progif == 2)
        show_parconfig_winbond(efer,key);
}

static void __devinit decode_smsc(int efer, int key, int devid, int devrev)
{
        const char *type = "unknown";
    void (*func)(int io, int key);
        int id;

        if (devid == devrev)
        /* simple heuristics, we happened to read some
                   non-smsc register */
        return;

    func=NULL;
        id=(devid<<8) | devrev;

    if    (id==0x0302) {type="37c669"; func=show_parconfig_smsc37c669;}
    else if    (id==0x6582) type="37c665IR";
    else if    (devid==0x65) type="37c665GT";
    else if    (devid==0x66) type="37c666GT";

    if (verbose_probing)
        printk(KERN_INFO "SMSC chip at EFER=0x%x "
               "key=0x%02x devid=%02x devrev=%02x type=%s\n",
               efer, key, devid, devrev, type);

    if (func)
        func(efer,key);
}


static void __devinit winbond_check(int io, int key)
{
    int devid,devrev,oldid,x_devid,x_devrev,x_oldid;

    /* First probe without key */
    outb(0x20,io);
    x_devid=inb(io+1);
    outb(0x21,io);
    x_devrev=inb(io+1);
    outb(0x09,io);
    x_oldid=inb(io+1);

    outb(key,io);
    outb(key,io);     /* Write Magic Sequence to EFER, extended
                             funtion enable register */
    outb(0x20,io);    /* Write EFIR, extended function index register */
    devid=inb(io+1);  /* Read EFDR, extended function data register */
    outb(0x21,io);
    devrev=inb(io+1);
    outb(0x09,io);
    oldid=inb(io+1);
    outb(0xaa,io);    /* Magic Seal */

    if ((x_devid == devid) && (x_devrev == devrev) && (x_oldid == oldid))
        return; /* protection against false positives */

    decode_winbond(io,key,devid,devrev,oldid);
}

static void __devinit winbond_check2(int io,int key)
{
        int devid,devrev,oldid,x_devid,x_devrev,x_oldid;

    /* First probe without the key */
    outb(0x20,io+2);
    x_devid=inb(io+2);
    outb(0x21,io+1);
    x_devrev=inb(io+2);
    outb(0x09,io+1);
    x_oldid=inb(io+2);

        outb(key,io);     /* Write Magic Byte to EFER, extended
                             funtion enable register */
        outb(0x20,io+2);  /* Write EFIR, extended function index register */
        devid=inb(io+2);  /* Read EFDR, extended function data register */
        outb(0x21,io+1);
        devrev=inb(io+2);
        outb(0x09,io+1);
        oldid=inb(io+2);
        outb(0xaa,io);    /* Magic Seal */

    if ((x_devid == devid) && (x_devrev == devrev) && (x_oldid == oldid))
        return; /* protection against false positives */

        decode_winbond(io,key,devid,devrev,oldid);
}

static void __devinit smsc_check(int io, int key)
{
        int id,rev,oldid,oldrev,x_id,x_rev,x_oldid,x_oldrev;

    /* First probe without the key */
    outb(0x0d,io);
    x_oldid=inb(io+1);
    outb(0x0e,io);
    x_oldrev=inb(io+1);
    outb(0x20,io);
    x_id=inb(io+1);
    outb(0x21,io);
    x_rev=inb(io+1);

        outb(key,io);
        outb(key,io);     /* Write Magic Sequence to EFER, extended
                             funtion enable register */
        outb(0x0d,io);    /* Write EFIR, extended function index register */
        oldid=inb(io+1);  /* Read EFDR, extended function data register */
        outb(0x0e,io);
        oldrev=inb(io+1);
    outb(0x20,io);
    id=inb(io+1);
    outb(0x21,io);
    rev=inb(io+1);
        outb(0xaa,io);    /* Magic Seal */

    if ((x_id == id) && (x_oldrev == oldrev) &&
        (x_oldid == oldid) && (x_rev == rev))
        return; /* protection against false positives */

        decode_smsc(io,key,oldid,oldrev);
}


static void __devinit detect_and_report_winbond (void)

    if (verbose_probing)
        printk(KERN_DEBUG "Winbond Super-IO detection, now testing ports 3F0,370,250,4E,2E ...\n");
    winbond_check(0x3f0,0x87);
    winbond_check(0x370,0x87);
    winbond_check(0x2e ,0x87);
    winbond_check(0x4e ,0x87);
    winbond_check(0x3f0,0x86);
    winbond_check2(0x250,0x88); 
    winbond_check2(0x250,0x89);
}

static void __devinit detect_and_report_smsc (void)
{
    if (verbose_probing)
        printk(KERN_DEBUG "SMSC Super-IO detection, now testing Ports 2F0, 370 ...\n");
    smsc_check(0x3f0,0x55);
    smsc_check(0x370,0x55);
    smsc_check(0x3f0,0x44);
    smsc_check(0x370,0x44);
}
#endif /* CONFIG_PARPORT_PC_SUPERIO */

static int __devinit get_superio_dma (struct parport *p)
{
    int i=0;
    while( (superios[i].io != p->base) && (i<NR_SUPERIOS))
        i++;
    if (i!=NR_SUPERIOS)
        return superios[i].dma;
    return PARPORT_DMA_NONE;
}

static int __devinit get_superio_irq (struct parport *p)
{
    int i=0;
        while( (superios[i].io != p->base) && (i<NR_SUPERIOS))
                i++;
        if (i!=NR_SUPERIOS)
                return superios[i].irq;
        return PARPORT_IRQ_NONE;
}
    

/* --- Mode detection ------------------------------------- */

/*
 * Checks for port existence, all ports support SPP MODE
 * Returns: 
 *         0           :  No parallel port at this adress
 *  PARPORT_MODE_PCSPP :  SPP port detected 
 *                        (if the user specified an ioport himself,
 *                         this shall always be the case!)
 *
 */
static int __devinit parport_SPP_supported(struct parport *pb)
{
    unsigned char r, w;

    /*
     * first clear an eventually pending EPP timeout 
     * I (sailer@ife.ee.ethz.ch) have an SMSC chipset
     * that does not even respond to SPP cycles if an EPP
     * timeout is pending
     */
    clear_epp_timeout(pb);

    /* Do a simple read-write test to make sure the port exists. */
    w = 0xc;
    outb (w, CONTROL (pb));

    /* Is there a control register that we can read from?  Some
     * ports don't allow reads, so read_control just returns a
     * software copy. Some ports _do_ allow reads, so bypass the
     * software copy here.  In addition, some bits aren't
     * writable. */
    r = inb (CONTROL (pb));
    if ((r & 0xf) == w) {
        w = 0xe;
        outb (w, CONTROL (pb));
        r = inb (CONTROL (pb));
        outb (0xc, CONTROL (pb));
        if ((r & 0xf) == w)
            return PARPORT_MODE_PCSPP;
    }

    if (user_specified)
        /* That didn't work, but the user thinks there's a
         * port here. */
        printk (KERN_INFO "parport 0x%lx (WARNING): CTR: "
            "wrote 0x%02x, read 0x%02x\n", pb->base, w, r);

    /* Try the data register.  The data lines aren't tri-stated at
     * this stage, so we expect back what we wrote. */
    w = 0xaa;
    parport_pc_write_data (pb, w);
    r = parport_pc_read_data (pb);
    if (r == w) {
        w = 0x55;
        parport_pc_write_data (pb, w);
        r = parport_pc_read_data (pb);
        if (r == w)
            return PARPORT_MODE_PCSPP;
    }

    if (user_specified) {
        /* Didn't work, but the user is convinced this is the
         * place. */
        printk (KERN_INFO "parport 0x%lx (WARNING): DATA: "
            "wrote 0x%02x, read 0x%02x\n", pb->base, w, r);
        printk (KERN_INFO "parport 0x%lx: You gave this address, "
            "but there is probably no parallel port there!\n",
            pb->base);
    }

    /* It's possible that we can't read the control register or
     * the data register.  In that case just believe the user. */
    if (user_specified)
        return PARPORT_MODE_PCSPP;

    return 0;
}

/* Check for ECR
 *
 * Old style XT ports alias io ports every 0x400, hence accessing ECR
 * on these cards actually accesses the CTR.
 *
 * Modern cards don't do this but reading from ECR will return 0xff
 * regardless of what is written here if the card does NOT support
 * ECP.
 *
 * We first check to see if ECR is the same as CTR.  If not, the low
 * two bits of ECR aren't writable, so we check by writing ECR and
 * reading it back to see if it's what we expect.
 */
static int __devinit parport_ECR_present(struct parport *pb)
{
    struct parport_pc_private *priv = pb->private_data;
    unsigned char r = 0xc;

    outb (r, CONTROL (pb));
    if ((inb (ECONTROL (pb)) & 0x3) == (r & 0x3)) {
        outb (r ^ 0x2, CONTROL (pb)); /* Toggle bit 1 */

        r = inb (CONTROL (pb));
        if ((inb (ECONTROL (pb)) & 0x2) == (r & 0x2))
            goto no_reg; /* Sure that no ECR register exists */
    }
    
    if ((inb (ECONTROL (pb)) & 0x3 ) != 0x1)
        goto no_reg;

    ECR_WRITE (pb, 0x34);
    if (inb (ECONTROL (pb)) != 0x35)
        goto no_reg;

    priv->ecr = 1;
    outb (0xc, CONTROL (pb));
    
    /* Go to mode 000 */
    frob_set_mode (pb, ECR_SPP);

    return 1;

 no_reg:
    outb (0xc, CONTROL (pb));
    return 0; 
}

#ifdef CONFIG_PARPORT_1284
/* Detect PS/2 support.
 *
 * Bit 5 (0x20) sets the PS/2 data direction; setting this high
 * allows us to read data from the data lines.  In theory we would get back
 * 0xff but any peripheral attached to the port may drag some or all of the
 * lines down to zero.  So if we get back anything that isn't the contents
 * of the data register we deem PS/2 support to be present. 
 *
 * Some SPP ports have "half PS/2" ability - you can't turn off the line
 * drivers, but an external peripheral with sufficiently beefy drivers of
 * its own can overpower them and assert its own levels onto the bus, from
 * where they can then be read back as normal.  Ports with this property
 * and the right type of device attached are likely to fail the SPP test,
 * (as they will appear to have stuck bits) and so the fact that they might
 * be misdetected here is rather academic. 
 */

static int __devinit parport_PS2_supported(struct parport *pb)
{
    int ok = 0;
  
    clear_epp_timeout(pb);

    /* try to tri-state the buffer */
    parport_pc_data_reverse (pb);
    
    parport_pc_write_data(pb, 0x55);
    if (parport_pc_read_data(pb) != 0x55) ok++;

    parport_pc_write_data(pb, 0xaa);
    if (parport_pc_read_data(pb) != 0xaa) ok++;

    /* cancel input mode */
    parport_pc_data_forward (pb);

    if (ok) {
        pb->modes |= PARPORT_MODE_TRISTATE;
    } else {
        struct parport_pc_private *priv = pb->private_data;
        priv->ctr_writable &= ~0x20;
    }

    return ok;
}

#ifdef CONFIG_PARPORT_PC_FIFO
static int __devinit parport_ECP_supported(struct parport *pb)
{
    int i;
    int config, configb;
    int pword;
    struct parport_pc_private *priv = pb->private_data;
    /* Translate ECP intrLine to ISA irq value */    
    static const int intrline[]= { 0, 7, 9, 10, 11, 14, 15, 5 }; 

    /* If there is no ECR, we have no hope of supporting ECP. */
    if (!priv->ecr)
        return 0;

    /* Find out FIFO depth */
    ECR_WRITE (pb, ECR_SPP << 5); /* Reset FIFO */
    ECR_WRITE (pb, ECR_TST << 5); /* TEST FIFO */
    for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02); i++)
        outb (0xaa, FIFO (pb));

    /*
     * Using LGS chipset it uses ECR register, but
     * it doesn't support ECP or FIFO MODE
     */
    if (i == 1024) {
        ECR_WRITE (pb, ECR_SPP << 5);
        return 0;
    }

    priv->fifo_depth = i;
    if (verbose_probing)
        printk (KERN_DEBUG "0x%lx: FIFO is %d bytes\n", pb->base, i);

    /* Find out writeIntrThreshold */
    frob_econtrol (pb, 1<<2, 1<<2);
    frob_econtrol (pb, 1<<2, 0);
    for (i = 1; i <= priv->fifo_depth; i++) {
        inb (FIFO (pb));
        udelay (50);
        if (inb (ECONTROL (pb)) & (1<<2))
            break;
    }

    if (i <= priv->fifo_depth) {
        if (verbose_probing)
            printk (KERN_DEBUG "0x%lx: writeIntrThreshold is %d\n",
                pb->base, i);
    } else
        /* Number of bytes we know we can write if we get an
                   interrupt. */
        i = 0;

    priv->writeIntrThreshold = i;

    /* Find out readIntrThreshold */
    frob_set_mode (pb, ECR_PS2); /* Reset FIFO and enable PS2 */
    parport_pc_data_reverse (pb); /* Must be in PS2 mode */
    frob_set_mode (pb, ECR_TST); /* Test FIFO */
    frob_econtrol (pb, 1<<2, 1<<2);
    frob_econtrol (pb, 1<<2, 0);
    for (i = 1; i <= priv->fifo_depth; i++) {
        outb (0xaa, FIFO (pb));
        if (inb (ECONTROL (pb)) & (1<<2))
            break;
    }

    if (i <= priv->fifo_depth) {
        if (verbose_probing)
            printk (KERN_INFO "0x%lx: readIntrThreshold is %d\n",
                pb->base, i);
    } else
        /* Number of bytes we can read if we get an interrupt. */
        i = 0;

    priv->readIntrThreshold = i;

    ECR_WRITE (pb, ECR_SPP << 5); /* Reset FIFO */
    ECR_WRITE (pb, 0xf4); /* Configuration mode */
    config = inb (CONFIGA (pb));
    pword = (config >> 4) & 0x7;
    switch (pword) {
    case 0:
        pword = 2;
        printk (KERN_WARNING "0x%lx: Unsupported pword size!\n",
            pb->base);
        break;
    case 2:
        pword = 4;
        printk (KERN_WARNING "0x%lx: Unsupported pword size!\n",
            pb->base);
        break;
    default:
        printk (KERN_WARNING "0x%lx: Unknown implementation ID\n",
            pb->base);
        /* Assume 1 */
    case 1:
        pword = 1;
    }
    priv->pword = pword;

    if (verbose_probing) {
        printk (KERN_DEBUG "0x%lx: PWord is %d bits\n", pb->base, 8 * pword);
        
        printk (KERN_DEBUG "0x%lx: Interrupts are ISA-%s\n", pb->base,
            config & 0x80 ? "Level" : "Pulses");

        configb = inb (CONFIGB (pb));
        printk (KERN_DEBUG "0x%lx: ECP port cfgA=0x%02x cfgB=0x%02x\n",
            pb->base, config, configb);
        printk (KERN_DEBUG "0x%lx: ECP settings irq=", pb->base);
        if ((configb >>3) & 0x07)
            printk("%d",intrline[(configb >>3) & 0x07]);
        else
            printk("<none or set by other means>");
        printk (" dma=");
        if( (configb & 0x03 ) == 0x00)
            printk("<none or set by other means>\n");
        else
            printk("%d\n",configb & 0x07);
    }

    /* Go back to mode 000 */
    frob_set_mode (pb, ECR_SPP);

    return 1;
}
#endif

static int __devinit parport_ECPPS2_supported(struct parport *pb)
{
    const struct parport_pc_private *priv = pb->private_data;
    int result;
    unsigned char oecr;

    if (!priv->ecr)
        return 0;

    oecr = inb (ECONTROL (pb));
    ECR_WRITE (pb, ECR_PS2 << 5);
    result = parport_PS2_supported(pb);
    ECR_WRITE (pb, oecr);
    return result;
}

/* EPP mode detection  */

static int __devinit parport_EPP_supported(struct parport *pb)
{
    const struct parport_pc_private *priv = pb->private_data;

    /*
     * Theory:
     *    Bit 0 of STR is the EPP timeout bit, this bit is 0
     *    when EPP is possible and is set high when an EPP timeout
     *    occurs (EPP uses the HALT line to stop the CPU while it does
     *    the byte transfer, an EPP timeout occurs if the attached
     *    device fails to respond after 10 micro seconds).
     *
     *    This bit is cleared by either reading it (National Semi)
     *    or writing a 1 to the bit (SMC, UMC, WinBond), others ???
     *    This bit is always high in non EPP modes.
     */

    /* If EPP timeout bit clear then EPP available */
    if (!clear_epp_timeout(pb)) {
        return 0;  /* No way to clear timeout */
    }

    /* Check for Intel bug. */
    if (priv->ecr) {
        unsigned char i;
        for (i = 0x00; i < 0x80; i += 0x20) {
            ECR_WRITE (pb, i);
            if (clear_epp_timeout (pb)) {
                /* Phony EPP in ECP. */
                return 0;
            }
        }
    }

    pb->modes |= PARPORT_MODE_EPP;

    /* Set up access functions to use EPP hardware. */
    pb->ops->epp_read_data = parport_pc_epp_read_data;
    pb->ops->epp_write_data = parport_pc_epp_write_data;
    pb->ops->epp_read_addr = parport_pc_epp_read_addr;
    pb->ops->epp_write_addr = parport_pc_epp_write_addr;

    return 1;
}

static int __devinit parport_ECPEPP_supported(struct parport *pb)
{
    struct parport_pc_private *priv = pb->private_data;
    int result;
    unsigned char oecr;

    if (!priv->ecr) {
        return 0;
    }

    oecr = inb (ECONTROL (pb));
    /* Search for SMC style EPP+ECP mode */
    ECR_WRITE (pb, 0x80);
    outb (0x04, CONTROL (pb));
    result = parport_EPP_supported(pb);

    ECR_WRITE (pb, oecr);

    if (result) {
        /* Set up access functions to use ECP+EPP hardware. */
        pb->ops->epp_read_data = parport_pc_ecpepp_read_data;
        pb->ops->epp_write_data = parport_pc_ecpepp_write_data;
        pb->ops->epp_read_addr = parport_pc_ecpepp_read_addr;
        pb->ops->epp_write_addr = parport_pc_ecpepp_write_addr;
    }

    return result;
}

#else /* No IEEE 1284 support */

/* Don't bother probing for modes we know we won't use. */
static int __devinit parport_PS2_supported(struct parport *pb) { return 0; }
#ifdef CONFIG_PARPORT_PC_FIFO
static int __devinit parport_ECP_supported(struct parport *pb) { return 0; }
#endif
static int __devinit parport_EPP_supported(struct parport *pb) { return 0; }
static int __devinit parport_ECPEPP_supported(struct parport *pb){return 0;}
static int __devinit parport_ECPPS2_supported(struct parport *pb){return 0;}

#endif /* No IEEE 1284 support */

/* --- IRQ detection -------------------------------------- */

/* Only if supports ECP mode */
static int __devinit programmable_irq_support(struct parport *pb)
{
    int irq, intrLine;
    unsigned char oecr = inb (ECONTROL (pb));
    static const int lookup[8] = {
        PARPORT_IRQ_NONE, 7, 9, 10, 11, 14, 15, 5
    };

    ECR_WRITE (pb, ECR_CNF << 5); /* Configuration MODE */

    intrLine = (inb (CONFIGB (pb)) >> 3) & 0x07;
    irq = lookup[intrLine];

    ECR_WRITE (pb, oecr);
    return irq;
}

static int __devinit irq_probe_ECP(struct parport *pb)
{
    int i;
    unsigned long irqs;

    sti();
    irqs = probe_irq_on();
        
    ECR_WRITE (pb, ECR_SPP << 5); /* Reset FIFO */
    ECR_WRITE (pb, (ECR_TST << 5) | 0x04);
    ECR_WRITE (pb, ECR_TST << 5);

    /* If Full FIFO sure that writeIntrThreshold is generated */
    for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02) ; i++) 
        outb (0xaa, FIFO (pb));
        
    pb->irq = probe_irq_off(irqs);
    ECR_WRITE (pb, ECR_SPP << 5);

    if (pb->irq <= 0)
        pb->irq = PARPORT_IRQ_NONE;

    return pb->irq;
}

/*
 * This detection seems that only works in National Semiconductors
 * This doesn't work in SMC, LGS, and Winbond 
 */
static int __devinit irq_probe_EPP(struct parport *pb)
{
#ifndef ADVANCED_DETECT
    return PARPORT_IRQ_NONE;
#else
    int irqs;
    unsigned char oecr;

    if (pb->modes & PARPORT_MODE_PCECR)
        oecr = inb (ECONTROL (pb));

    sti();
    irqs = probe_irq_on();

    if (pb->modes & PARPORT_MODE_PCECR)
        frob_econtrol (pb, 0x10, 0x10);
    
    clear_epp_timeout(pb);
    parport_pc_frob_control (pb, 0x20, 0x20);
    parport_pc_frob_control (pb, 0x10, 0x10);
    clear_epp_timeout(pb);

    /* Device isn't expecting an EPP read
     * and generates an IRQ.
     */
    parport_pc_read_epp(pb);
    udelay(20);

    pb->irq = probe_irq_off (irqs);
    if (pb->modes & PARPORT_MODE_PCECR)
        ECR_WRITE (pb, oecr);
    parport_pc_write_control(pb, 0xc);

    if (pb->irq <= 0)
        pb->irq = PARPORT_IRQ_NONE;

    return pb->irq;
#endif /* Advanced detection */
}

static int __devinit irq_probe_SPP(struct parport *pb)
{
    /* Don't even try to do this. */
    return PARPORT_IRQ_NONE;
}

/* We will attempt to share interrupt requests since other devices
 * such as sound cards and network cards seem to like using the
 * printer IRQs.
 *
 * When ECP is available we can autoprobe for IRQs.
 * NOTE: If we can autoprobe it, we can register the IRQ.
 */
static int __devinit parport_irq_probe(struct parport *pb)
{
    struct parport_pc_private *priv = pb->private_data;

    priv->ctr_writable |= 0x10;

    if (priv->ecr) {
        pb->irq = programmable_irq_support(pb);

        if (pb->irq == PARPORT_IRQ_NONE)
            pb->irq = irq_probe_ECP(pb);
    }

    if ((pb->irq == PARPORT_IRQ_NONE) && priv->ecr &&
        (pb->modes & PARPORT_MODE_EPP))
        pb->irq = irq_probe_EPP(pb);

    clear_epp_timeout(pb);

    if (pb->irq == PARPORT_IRQ_NONE && (pb->modes & PARPORT_MODE_EPP))
        pb->irq = irq_probe_EPP(pb);

    clear_epp_timeout(pb);

    if (pb->irq == PARPORT_IRQ_NONE)
        pb->irq = irq_probe_SPP(pb);

    if (pb->irq == PARPORT_IRQ_NONE)
        pb->irq = get_superio_irq(pb);

    if (pb->irq == PARPORT_IRQ_NONE)
        priv->ctr_writable &= ~0x10;

    return pb->irq;
}

/* --- DMA detection -------------------------------------- */

/* Only if chipset conforms to ECP ISA Interface Standard */
static int __devinit programmable_dma_support (struct parport *p)
{
    unsigned char oecr = inb (ECONTROL (p));
    int dma;

    frob_set_mode (p, ECR_CNF);
    
    dma = inb (CONFIGB(p)) & 0x07;
    /* 000: Indicates jumpered 8-bit DMA if read-only.
       100: Indicates jumpered 16-bit DMA if read-only. */
    if ((dma & 0x03) == 0)
        dma = PARPORT_DMA_NONE;

    ECR_WRITE (p, oecr);
    return dma;
}

static int __devinit parport_dma_probe (struct parport *p)
{
    const struct parport_pc_private *priv = p->private_data;
    if (priv->ecr)
        p->dma = programmable_dma_support(p); /* ask ECP chipset first */
    if (p->dma == PARPORT_DMA_NONE) {
        /* ask known Super-IO chips proper, although these
           claim ECP compatible, some don't report their DMA
           conforming to ECP standards */
        p->dma = get_superio_dma(p);
    }

    return p->dma;
}

/* --- Initialisation code -------------------------------- */

struct parport *parport_pc_probe_port (unsigned long int base,
                       unsigned long int base_hi,
                       int irq, int dma,
                       struct pci_dev *dev)
{
    struct parport_pc_private *priv;
    struct parport_operations *ops;
    struct parport tmp;
    struct parport *p = &tmp;
    int probedirq = PARPORT_IRQ_NONE;
    if (check_region(base, 3)) return NULL;
    priv = kmalloc (sizeof (struct parport_pc_private), GFP_KERNEL);
    if (!priv) {
        printk (KERN_DEBUG "parport (0x%lx): no memory!\n", base);
        return NULL;
    }
    ops = kmalloc (sizeof (struct parport_operations), GFP_KERNEL);
    if (!ops) {
        printk (KERN_DEBUG "parport (0x%lx): no memory for ops!\n",
            base);
        kfree (priv);
        return NULL;
    }
    memcpy (ops, &parport_pc_ops, sizeof (struct parport_operations));
    priv->ctr = 0xc;
    priv->ctr_writable = ~0x10;
    priv->ecr = 0;
    priv->fifo_depth = 0;
    priv->dma_buf = 0;
    priv->dma_handle = 0;
    priv->dev = dev;
    p->base = base;
    p->base_hi = base_hi;
    p->irq = irq;
    p->dma = dma;
    p->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT;
    p->ops = ops;
    p->private_data = priv;
    p->physport = p;

    if (base_hi && !check_region(base_hi,3))
        parport_ECR_present(p);

    if (base != 0x3bc) {
        if (!check_region(base+0x3, 5)) {
            if (!parport_EPP_supported(p))
                parport_ECPEPP_supported(p);
        }
    }
    if (!parport_SPP_supported (p)) {
        /* No port. */
        kfree (priv);
        kfree (ops);
        return NULL;
    }
    if (priv->ecr)
        parport_ECPPS2_supported(p);
    else
        parport_PS2_supported (p);

    if (!(p = parport_register_port(base, PARPORT_IRQ_NONE,
                    PARPORT_DMA_NONE, ops))) {
        kfree (priv);
        kfree (ops);
        return NULL;
    }

    p->base_hi = base_hi;
    p->modes = tmp.modes;
    p->size = (p->modes & PARPORT_MODE_EPP)?8:3;
    p->private_data = priv;

    printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base);
    if (p->base_hi && priv->ecr)
        printk(" (0x%lx)", p->base_hi);
    p->irq = irq;
    p->dma = dma;
    if (p->irq == PARPORT_IRQ_AUTO) {
        p->irq = PARPORT_IRQ_NONE;
        parport_irq_probe(p);
    } else if (p->irq == PARPORT_IRQ_PROBEONLY) {
        p->irq = PARPORT_IRQ_NONE;
        parport_irq_probe(p);
        probedirq = p->irq;
        p->irq = PARPORT_IRQ_NONE;
    }
    if (p->irq != PARPORT_IRQ_NONE) {
        printk(", irq %d", p->irq);

        if (p->dma == PARPORT_DMA_AUTO) {
            p->dma = PARPORT_DMA_NONE;
            parport_dma_probe(p);
        }
    }
    if (p->dma == PARPORT_DMA_AUTO) /* To use DMA, giving the irq
                                           is mandatory (see above) */
        p->dma = PARPORT_DMA_NONE;

#ifdef CONFIG_PARPORT_PC_FIFO
    if (parport_ECP_supported(p) &&
        p->dma != PARPORT_DMA_NOFIFO &&
        priv->fifo_depth > 0 && p->irq != PARPORT_IRQ_NONE) {
        p->modes |= PARPORT_MODE_ECP | PARPORT_MODE_COMPAT;
        p->ops->compat_write_data = parport_pc_compat_write_block_pio;
#ifdef CONFIG_PARPORT_1284
        p->ops->ecp_write_data = parport_pc_ecp_write_block_pio;
        /* currently broken, but working on it.. (FB) */
        /* p->ops->ecp_read_data = parport_pc_ecp_read_block_pio; */
#endif /* IEEE 1284 support */
        if (p->dma != PARPORT_DMA_NONE) {
            printk(", dma %d", p->dma);
            p->modes |= PARPORT_MODE_DMA;
        }
        else printk(", using FIFO");
    }
    else
        /* We can't use the DMA channel after all. */
        p->dma = PARPORT_DMA_NONE;
#endif /* Allowed to use FIFO/DMA */

    printk(" [");
#define printmode(x) {if(p->modes&PARPORT_MODE_##x){printk("%s%s",f?",":"",#x);f++;}}
    {
        int f = 0;
        printmode(PCSPP);
        printmode(TRISTATE);
        printmode(COMPAT)
        printmode(EPP);
        printmode(ECP);
        printmode(DMA);
    }
#undef printmode
#ifndef CONFIG_PARPORT_1284
    printk ("(,...)");
#endif /* CONFIG_PARPORT_1284 */
    printk("]\n");
    if (probedirq != PARPORT_IRQ_NONE) 
        printk(KERN_INFO "%s: irq %d detected\n", p->name, probedirq);
    parport_proc_register(p);

    request_region (p->base, 3, p->name);
    if (p->size > 3)
        request_region (p->base + 3, p->size - 3, p->name);
    if (p->modes & PARPORT_MODE_ECP)
        request_region (p->base_hi, 3, p->name);

    if (p->irq != PARPORT_IRQ_NONE) {
        if (request_irq (p->irq, parport_pc_interrupt,
                 0, p->name, p)) {
            printk (KERN_WARNING "%s: irq %d in use, "
                "resorting to polled operation\n",
                p->name, p->irq);
            p->irq = PARPORT_IRQ_NONE;
            p->dma = PARPORT_DMA_NONE;
        }

#ifdef CONFIG_PARPORT_PC_FIFO
        if (p->dma != PARPORT_DMA_NONE) {
            if (request_dma (p->dma, p->name)) {
                printk (KERN_WARNING "%s: dma %d in use, "
                    "resorting to PIO operation\n",
                    p->name, p->dma);
                p->dma = PARPORT_DMA_NONE;
            } else {
                priv->dma_buf =
                  pci_alloc_consistent(priv->dev,
                               PAGE_SIZE,
                               &priv->dma_handle);
                if (! priv->dma_buf) {
                    printk (KERN_WARNING "%s: "
                        "cannot get buffer for DMA, "
                        "resorting to PIO operation\n",
                        p->name);
                    free_dma(p->dma);
                    p->dma = PARPORT_DMA_NONE;
                }
            }
        }
#endif /* CONFIG_PARPORT_PC_FIFO */
    }

    /* Done probing.  Now put the port into a sensible start-up state. */
    if (priv->ecr)
        /*
         * Put the ECP detected port in PS2 mode.
         * Do this also for ports that have ECR but don't do ECP.
         */
        ECR_WRITE (p, 0x34);

    parport_pc_write_data(p, 0);
    parport_pc_data_forward (p);

    /* Now that we've told the sharing engine about the port, and
       found out its characteristics, let the high-level drivers
       know about it. */
    parport_announce_port (p);

    return p;
}

void parport_pc_unregister_port (struct parport *p)
{
    struct parport_pc_private *priv = p->private_data;
    struct parport_operations *ops = p->ops;
    if (p->dma != PARPORT_DMA_NONE)
        free_dma(p->dma);
    if (p->irq != PARPORT_IRQ_NONE)
        free_irq(p->irq, p);
    release_region(p->base, 3);
    if (p->size > 3)
        release_region(p->base + 3, p->size - 3);
    if (p->modes & PARPORT_MODE_ECP)
        release_region(p->base_hi, 3);
    parport_proc_unregister(p);
    if (priv->dma_buf)
        pci_free_consistent(priv->dev, PAGE_SIZE,
                    priv->dma_buf,
                    priv->dma_handle);
    kfree (p->private_data);
    parport_unregister_port(p);
    kfree (ops); /* hope no-one cached it */
}

#ifdef CONFIG_PCI

/* ITE support maintained by Rich Liu <richliu@poorman.org> */
static int __devinit sio_ite_8872_probe (struct pci_dev *pdev, int autoirq,
                     int autodma)
{
    short inta_addr[6] = { 0x2A0, 0x2C0, 0x220, 0x240, 0x1E0 };
    u32 ite8872set;
    u32 ite8872_lpt, ite8872_lpthi;
    u8 ite8872_irq, type;
    int irq;
    int i;

    DPRINTK (KERN_DEBUG "sio_ite_8872_probe()\n");
    
    // make sure which one chip
    for(i = 0; i < 5; i++) {
        if (check_region (inta_addr[i], 0x8) >= 0) {
            int test;
            pci_write_config_dword (pdev, 0x60,
                        0xe7000000 | inta_addr[i]);
            pci_write_config_dword (pdev, 0x78,
                        0x00000000 | inta_addr[i]);
            test = inb (inta_addr[i]);
            if (test != 0xff) break;
        }
    }
    if(i >= 5) {
        printk (KERN_INFO "parport_pc: cannot find ITE8872 INTA\n");
        return 0;
    }

    type = inb (inta_addr[i] + 0x18);
    type &= 0x0f;

    switch (type) {
    case 0x2:
        printk (KERN_INFO "parport_pc: ITE8871 found (1P)\n");
        ite8872set = 0x64200000;
        break;
    case 0xa:
        printk (KERN_INFO "parport_pc: ITE8875 found (1P)\n");
        ite8872set = 0x64200000;
        break;
    case 0xe:
        printk (KERN_INFO "parport_pc: ITE8872 found (2S1P)\n");
        ite8872set = 0x64e00000;
        break;
    case 0x6:
        printk (KERN_INFO "parport_pc: ITE8873 found (1S)\n");
        return 0;
    case 0x8:
        DPRINTK (KERN_DEBUG "parport_pc: ITE8874 found (2S)\n");
        return 0;
    default:
        printk (KERN_INFO "parport_pc: unknown ITE887x\n");
        printk (KERN_INFO "parport_pc: please mail 'lspci -nvv' "
            "output to Rich.Liu@ite.com.tw\n");
        return 0;
    }

    pci_read_config_byte (pdev, 0x3c, &ite8872_irq);
    pci_read_config_dword (pdev, 0x1c, &ite8872_lpt);
    ite8872_lpt &= 0x0000ff00;
    pci_read_config_dword (pdev, 0x20, &ite8872_lpthi);
    ite8872_lpthi &= 0x0000ff00;
    pci_write_config_dword (pdev, 0x6c, 0xe3000000 | ite8872_lpt);
    pci_write_config_dword (pdev, 0x70, 0xe3000000 | ite8872_lpthi);
    pci_write_config_dword (pdev, 0x80, (ite8872_lpthi<<16) | ite8872_lpt);
    // SET SPP&EPP , Parallel Port NO DMA , Enable All Function
    // SET Parallel IRQ
    pci_write_config_dword (pdev, 0x9c,
                ite8872set | (ite8872_irq * 0x11111));

    DPRINTK (KERN_DEBUG "ITE887x: The IRQ is %d.\n", ite8872_irq);
    DPRINTK (KERN_DEBUG "ITE887x: The PARALLEL I/O port is 0x%x.\n",
         ite8872_lpt);
    DPRINTK (KERN_DEBUG "ITE887x: The PARALLEL I/O porthi is 0x%x.\n",
         ite8872_lpthi);

    /* Let the user (or defaults) steer us away from interrupts */
    irq = ite8872_irq;
    if (autoirq != PARPORT_IRQ_AUTO)
        irq = PARPORT_IRQ_NONE;

    if (parport_pc_probe_port (ite8872_lpt, ite8872_lpthi,
                   irq, PARPORT_DMA_NONE, NULL)) {
        printk (KERN_INFO
            "parport_pc: ITE 8872 parallel port: io=0x%X",
            ite8872_lpt);
        if (irq != PARPORT_IRQ_NONE)
            printk (", irq=%d", irq);
        printk ("\n");
        return 1;
    }

    return 0;
}

/* Via support maintained by Jeff Garzik <jgarzik@mandrakesoft.com> */
static int __devinit sio_via_686a_probe (struct pci_dev *pdev, int autoirq,
                     int autodma)
{
    u8 tmp;
    int dma, irq;
    unsigned port1, port2, have_eppecp;

    /*
     * unlock super i/o configuration, set 0x85_1
     */
    pci_read_config_byte (pdev, 0x85, &tmp);
    tmp |= (1 << 1);
    pci_write_config_byte (pdev, 0x85, tmp);
    
    /* 
     * Super I/O configuration, index port == 3f0h, data port == 3f1h
     */
    
    /* 0xE2_1-0: Parallel Port Mode / Enable */
    outb (0xE2, 0x3F0);
    tmp = inb (0x3F1);
    
    if ((tmp & 0x03) == 0x03) {
        printk (KERN_INFO "parport_pc: Via 686A parallel port disabled in BIOS\n");
        return 0;
    }
    
    /* 0xE6: Parallel Port I/O Base Address, bits 9-2 */
    outb (0xE6, 0x3F0);
    port1 = inb (0x3F1) << 2;
    
    switch (port1) {
    case 0x3bc: port2 = 0x7bc; break;
    case 0x378: port2 = 0x778; break;
    case 0x278: port2 = 0x678; break;
    default:
        printk (KERN_INFO "parport_pc: Weird Via 686A parport base 0x%X, ignoring\n",
            port1);
        return 0;
    }

    /* 0xF0_5: EPP+ECP enable */
    outb (0xF0, 0x3F0);
    have_eppecp = (inb (0x3F1) & (1 << 5));
    
    /*
     * lock super i/o configuration, clear 0x85_1
     */
    pci_read_config_byte (pdev, 0x85, &tmp);
    tmp &= ~(1 << 1);
    pci_write_config_byte (pdev, 0x85, tmp);

    /*
     * Get DMA and IRQ from PCI->ISA bridge PCI config registers
     */

    /* 0x50_3-2: PnP Routing for Parallel Port DRQ */
    pci_read_config_byte (pdev, 0x50, &tmp);
    dma = ((tmp >> 2) & 0x03);
    
    /* 0x51_7-4: PnP Routing for Parallel Port IRQ */
    pci_read_config_byte (pdev, 0x51, &tmp);
    irq = ((tmp >> 4) & 0x0F);

    /* filter bogus IRQs */
    switch (irq) {
    case 0:
    case 2:
    case 8:
    case 13:
        irq = PARPORT_IRQ_NONE;
        break;

    default: /* do nothing */
        break;
    }

    /* if ECP not enabled, DMA is not enabled, assumed bogus 'dma' value */
    if (!have_eppecp)
        dma = PARPORT_DMA_NONE;

    /* Let the user (or defaults) steer us away from interrupts and DMA */
    if (autoirq != PARPORT_IRQ_AUTO) {
        irq = PARPORT_IRQ_NONE;
        dma = PARPORT_DMA_NONE;
    }
    if (autodma != PARPORT_DMA_AUTO)
        dma = PARPORT_DMA_NONE;

    /* finally, do the probe with values obtained */
    if (parport_pc_probe_port (port1, port2, irq, dma, NULL)) {
        printk (KERN_INFO
            "parport_pc: Via 686A parallel port: io=0x%X", port1);
        if (irq != PARPORT_IRQ_NONE)
            printk (", irq=%d", irq);
        if (dma != PARPORT_DMA_NONE)
            printk (", dma=%d", dma);
        printk ("\n");
        return 1;
    }
    
    printk (KERN_WARNING "parport_pc: Strange, can't probe Via 686A parallel port: io=0x%X, irq=%d, dma=%d\n",
        port1, irq, dma);
    return 0;
}


enum parport_pc_sio_types {
    sio_via_686a = 0,    /* Via VT82C686A motherboard Super I/O */
    sio_ite_8872,
    last_sio
};

/* each element directly indexed from enum list, above */
static struct parport_pc_superio {
    int (*probe) (struct pci_dev *pdev, int autoirq, int autodma);
} parport_pc_superio_info[] __devinitdata = {
    { sio_via_686a_probe, },
    { sio_ite_8872_probe, },
};


enum parport_pc_pci_cards {
    siig_1s1p_10x_550 = last_sio,
    siig_1s1p_10x_650,
    siig_1s1p_10x_850,
    siig_1p_10x,
    siig_2p_10x,
    siig_2s1p_10x_550,
    siig_2s1p_10x_650,
    siig_2s1p_10x_850,
    siig_1p_20x,
    siig_2p_20x,
    siig_2p1s_20x_550,
    siig_2p1s_20x_650,
    siig_2p1s_20x_850,
    siig_1s1p_20x_550,
    siig_1s1p_20x_650,
    siig_1s1p_20x_850,
    siig_2s1p_20x_550,
    siig_2s1p_20x_650,
    siig_2s1p_20x_850,
    lava_parallel,
    lava_parallel_dual_a,
    lava_parallel_dual_b,
    boca_ioppar,
    plx_9050,
    timedia_4078a,
    timedia_4079h,
    timedia_4085h,
    timedia_4088a,
    timedia_4089a,
    timedia_4095a,
    timedia_4096a,
    timedia_4078u,
    timedia_4079a,
    timedia_4085u,
    timedia_4079r,
    timedia_4079s,
    timedia_4079d,
    timedia_4079e,
    timedia_4079f,
    timedia_9079a,
    timedia_9079b,
    timedia_9079c,
    timedia_4006a,
    timedia_4014,
    timedia_4008a,
    timedia_4018,
    timedia_9018a,
    syba_2p_epp,
    syba_1p_ecp,
    titan_010l,
    titan_1284p2,
    avlab_1p,
    avlab_2p,
    oxsemi_954,
    oxsemi_840,
    aks_0100,
};


/* each element directly indexed from enum list, above 
 * (but offset by last_sio) */
static struct parport_pc_pci {
    int numports;
    struct { /* BAR (base address registers) numbers in the config
                    space header */
        int lo;
        int hi; /* -1 if not there, >6 for offset-method (max
                           BAR is 6) */
    } addr[4];
} cards[] __devinitdata = {
    /* siig_1s1p_10x_550 */        { 1, { { 3, 4 }, } },
    /* siig_1s1p_10x_650 */        { 1, { { 3, 4 }, } },
    /* siig_1s1p_10x_850 */        { 1, { { 3, 4 }, } },
    /* siig_1p_10x */        { 1, { { 2, 3 }, } },
    /* siig_2p_10x */        { 2, { { 2, 3 }, { 4, 5 }, } },
    /* siig_2s1p_10x_550 */        { 1, { { 4, 5 }, } },
    /* siig_2s1p_10x_650 */        { 1, { { 4, 5 }, } },
    /* siig_2s1p_10x_850 */        { 1, { { 4, 5 }, } },
    /* siig_1p_20x */        { 1, { { 0, 1 }, } },
    /* siig_2p_20x */        { 2, { { 0, 1 }, { 2, 3 }, } },
    /* siig_2p1s_20x_550 */        { 2, { { 1, 2 }, { 3, 4 }, } },
    /* siig_2p1s_20x_650 */        { 2, { { 1, 2 }, { 3, 4 }, } },
    /* siig_2p1s_20x_850 */        { 2, { { 1, 2 }, { 3, 4 }, } },
    /* siig_1s1p_20x_550 */        { 1, { { 1, 2 }, } },
    /* siig_1s1p_20x_650 */        { 1, { { 1, 2 }, } },
    /* siig_1s1p_20x_850 */        { 1, { { 1, 2 }, } },
    /* siig_2s1p_20x_550 */        { 1, { { 2, 3 }, } },
    /* siig_2s1p_20x_650 */        { 1, { { 2, 3 }, } },
    /* siig_2s1p_20x_850 */        { 1, { { 2, 3 }, } },
    /* lava_parallel */        { 1, { { 0, -1 }, } },
    /* lava_parallel_dual_a */    { 1, { { 0, -1 }, } },
    /* lava_parallel_dual_b */    { 1, { { 0, -1 }, } },
    /* boca_ioppar */        { 1, { { 0, -1 }, } },
    /* plx_9050 */            { 2, { { 4, -1 }, { 5, -1 }, } },
    /* timedia_4078a */        { 1, { { 2, -1 }, } },
    /* timedia_4079h */             { 1, { { 2, 3 }, } },
    /* timedia_4085h */             { 2, { { 2, -1 }, { 4, -1 }, } },
    /* timedia_4088a */             { 2, { { 2, 3 }, { 4, 5 }, } },
    /* timedia_4089a */             { 2, { { 2, 3 }, { 4, 5 }, } },
    /* timedia_4095a */             { 2, { { 2, 3 }, { 4, 5 }, } },
    /* timedia_4096a */             { 2, { { 2, 3 }, { 4, 5 }, } },
    /* timedia_4078u */             { 1, { { 2, -1 }, } },
    /* timedia_4079a */             { 1, { { 2, 3 }, } },
    /* timedia_4085u */             { 2, { { 2, -1 }, { 4, -1 }, } },
    /* timedia_4079r */             { 1, { { 2, 3 }, } },
    /* timedia_4079s */             { 1, { { 2, 3 }, } },
    /* timedia_4079d */             { 1, { { 2, 3 }, } },
    /* timedia_4079e */             { 1, { { 2, 3 }, } },
    /* timedia_4079f */             { 1, { { 2, 3 }, } },
    /* timedia_9079a */             { 1, { { 2, 3 }, } },
    /* timedia_9079b */             { 1, { { 2, 3 }, } },
    /* timedia_9079c */             { 1, { { 2, 3 }, } },
    /* timedia_4006a */             { 1, { { 0, -1 }, } },
    /* timedia_4014  */             { 2, { { 0, -1 }, { 2, -1 }, } },
    /* timedia_4008a */             { 1, { { 0, 1 }, } },
    /* timedia_4018  */             { 2, { { 0, 1 }, { 2, 3 }, } },
    /* timedia_9018a */             { 2, { { 0, 1 }, { 2, 3 }, } },
                    /* SYBA uses fixed offsets in
                                           a 1K io window */
    /* syba_2p_epp AP138B */    { 2, { { 0, 0x078 }, { 0, 0x178 }, } },
    /* syba_1p_ecp W83787 */    { 1, { { 0, 0x078 }, } },
    /* titan_010l */        { 1, { { 3, -1 }, } },
    /* titan_1284p2 */        { 2, { { 0, 1 }, { 2, 3 }, } },
    /* avlab_1p        */    { 1, { { 0, 1}, } },
    /* avlab_2p        */    { 2, { { 0, 1}, { 2, 3 },} },
    /* The Oxford Semi cards are unusual: 954 doesn't support ECP,
     * and 840 locks up if you write 1 to bit 2! */
    /* oxsemi_954 */        { 1, { { 0, -1 }, } },
    /* oxsemi_840 */        { 1, { { 0, -1 }, } },
    /* aks_0100 */            { 1, { { 0, 1 }, } },
};

static struct pci_device_id parport_pc_pci_tbl[] __devinitdata = {
    /* Super-IO onboard chips */
    { 0x1106, 0x0686, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sio_via_686a },
    { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8872,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, sio_ite_8872 },

    /* PCI cards */
    { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x_550 },
    { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x_650 },
    { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x_850 },
    { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1P_10x,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1p_10x },
    { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P_10x,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p_10x },
    { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x_550 },
    { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x_650 },
    { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x_850 },
    { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1P_20x,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1p_20x },
    { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P_20x,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p_20x },
    { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x_550 },
    { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x_650 },
    { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x_850 },
    { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x_550 },
    { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_20x_650 },
    { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_20x_850 },
    { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x_550 },
    { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x_650 },
    { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x_850 },
    { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PARALLEL,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, lava_parallel },
    { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_A,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, lava_parallel_dual_a },
    { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_B,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, lava_parallel_dual_b },
    { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_BOCA_IOPPAR,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, boca_ioppar },
    { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
      PCI_SUBVENDOR_ID_EXSYS, PCI_SUBDEVICE_ID_EXSYS_4014, 0,0, plx_9050 },
    /* PCI_VENDOR_ID_TIMEDIA/SUNIX has many differing cards ...*/
    { 0x1409, 0x7168, 0x1409, 0x4078, 0, 0, timedia_4078a },
    { 0x1409, 0x7168, 0x1409, 0x4079, 0, 0, timedia_4079h },
    { 0x1409, 0x7168, 0x1409, 0x4085, 0, 0, timedia_4085h },
    { 0x1409, 0x7168, 0x1409, 0x4088, 0, 0, timedia_4088a },
    { 0x1409, 0x7168, 0x1409, 0x4089, 0, 0, timedia_4089a },
    { 0x1409, 0x7168, 0x1409, 0x4095, 0, 0, timedia_4095a },
    { 0x1409, 0x7168, 0x1409, 0x4096, 0, 0, timedia_4096a },
    { 0x1409, 0x7168, 0x1409, 0x5078, 0, 0, timedia_4078u },
    { 0x1409, 0x7168, 0x1409, 0x5079, 0, 0, timedia_4079a },
    { 0x1409, 0x7168, 0x1409, 0x5085, 0, 0, timedia_4085u },
    { 0x1409, 0x7168, 0x1409, 0x6079, 0, 0, timedia_4079r },
    { 0x1409, 0x7168, 0x1409, 0x7079, 0, 0, timedia_4079s },
    { 0x1409, 0x7168, 0x1409, 0x8079, 0, 0, timedia_4079d },
    { 0x1409, 0x7168, 0x1409, 0x9079, 0, 0, timedia_4079e },
    { 0x1409, 0x7168, 0x1409, 0xa079, 0, 0, timedia_4079f },
    { 0x1409, 0x7168, 0x1409, 0xb079, 0, 0, timedia_9079a },
    { 0x1409, 0x7168, 0x1409, 0xc079, 0, 0, timedia_9079b },
    { 0x1409, 0x7168, 0x1409, 0xd079, 0, 0, timedia_9079c },
    { 0x1409, 0x7268, 0x1409, 0x0101, 0, 0, timedia_4006a },
    { 0x1409, 0x7268, 0x1409, 0x0102, 0, 0, timedia_4014 },
    { 0x1409, 0x7268, 0x1409, 0x0103, 0, 0, timedia_4008a },
    { 0x1409, 0x7268, 0x1409, 0x0104, 0, 0, timedia_4018 },
    { 0x1409, 0x7268, 0x1409, 0x9018, 0, 0, timedia_9018a },
    { PCI_VENDOR_ID_SYBA, PCI_DEVICE_ID_SYBA_2P_EPP,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, syba_2p_epp },
    { PCI_VENDOR_ID_SYBA, PCI_DEVICE_ID_SYBA_1P_ECP,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, syba_1p_ecp },
    { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_010L,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_010l },
    { 0x9710, 0x9815, 0x1000, 0x0020, 0, 0, titan_1284p2 },
    /* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/
    { 0x14db, 0x2120, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1p}, /* AFAVLAB_TK9902 */
    { 0x14db, 0x2121, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2p},
    { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954PP,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_954 },
    { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_12PCI840,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_840 },
    { PCI_VENDOR_ID_AKS, PCI_DEVICE_ID_AKS_ALADDINCARD,
      PCI_ANY_ID, PCI_ANY_ID, 0, 0, aks_0100 },
    { 0, } /* terminate list */
};
MODULE_DEVICE_TABLE(pci,parport_pc_pci_tbl);

static int __devinit parport_pc_pci_probe (struct pci_dev *dev,
                       const struct pci_device_id *id)
{
    int err, count, n, i = id->driver_data;
    if (i < last_sio)
        /* This is an onboard Super-IO and has already been probed */
        return 0;

    /* This is a PCI card */
    i -= last_sio;
    count = 0;
    if ((err = pci_enable_device (dev)) != 0)
        return err;

    for (n = 0; n < cards[i].numports; n++) {
        int lo = cards[i].addr[n].lo;
        int hi = cards[i].addr[n].hi;
        unsigned long io_lo, io_hi;
        io_lo = pci_resource_start (dev, lo);
        io_hi = 0;
        if ((hi >= 0) && (hi <= 6))
            io_hi = pci_resource_start (dev, hi);
        else if (hi > 6)
            io_lo += hi; /* Reinterpret the meaning of
                                        "hi" as an offset (see SYBA
                                        def.) */
        /* TODO: test if sharing interrupts works */
        printk (KERN_DEBUG "PCI parallel port detected: %04x:%04x, "
            "I/O at %#lx(%#lx)\n",
            parport_pc_pci_tbl[i + last_sio].vendor,
            parport_pc_pci_tbl[i + last_sio].device, io_lo, io_hi);
        if (parport_pc_probe_port (io_lo, io_hi, PARPORT_IRQ_NONE,
                       PARPORT_DMA_NONE, dev))
            count++;
    }

    return count == 0 ? -ENODEV : 0;
}

static struct pci_driver parport_pc_pci_driver = {
    name:        "parport_pc",
    id_table:    parport_pc_pci_tbl,
    probe:        parport_pc_pci_probe,
};

static int __init parport_pc_init_superio (int autoirq, int autodma)
{
    const struct pci_device_id *id;
    struct pci_dev *pdev;
    int ret = 0;

    pci_for_each_dev(pdev) {
        id = pci_match_device (parport_pc_pci_tbl, pdev);
        if (id == NULL || id->driver_data >= last_sio)
            continue;

        if (parport_pc_superio_info[id->driver_data].probe
            (pdev, autoirq, autodma)) {
            ret++;
        }
    }

    return ret; /* number of devices found */
}
#else
static struct pci_driver parport_pc_pci_driver;
static int __init parport_pc_init_superio(int autoirq, int autodma) {return 0;}
#endif /* CONFIG_PCI */

/* This is called by parport_pc_find_nonpci_ports (in asm/parport.h) */
static int __init __attribute__((unused))
parport_pc_find_isa_ports (int autoirq, int autodma)
{
    int count = 0;

    if (parport_pc_probe_port(0x3bc, 0x7bc, autoirq, autodma, NULL))
        count++;
    if (parport_pc_probe_port(0x378, 0x778, autoirq, autodma, NULL))
        count++;
    if (parport_pc_probe_port(0x278, 0x678, autoirq, autodma, NULL))
        count++;

    return count;
}

/* This function is called by parport_pc_init if the user didn't
 * specify any ports to probe.  Its job is to find some ports.  Order
 * is important here -- we want ISA ports to be registered first,
 * followed by PCI cards (for least surprise), but before that we want
 * to do chipset-specific tests for some onboard ports that we know
 * about.
 *
 * autoirq is PARPORT_IRQ_NONE, PARPORT_IRQ_AUTO, or PARPORT_IRQ_PROBEONLY
 * autodma is PARPORT_DMA_NONE or PARPORT_DMA_AUTO
 */
static int __init parport_pc_find_ports (int autoirq, int autodma)
{
    int count = 0, r;

#ifdef CONFIG_PARPORT_PC_SUPERIO
    detect_and_report_winbond ();
    detect_and_report_smsc ();
#endif

    /* Onboard SuperIO chipsets that show themselves on the PCI bus. */
    count += parport_pc_init_superio (autoirq, autodma);

    /* ISA ports and whatever (see asm/parport.h). */
    count += parport_pc_find_nonpci_ports (autoirq, autodma);

    r = pci_register_driver (&parport_pc_pci_driver);
    if (r >= 0) {
        registered_parport = 1;
        count += r;
    }

    return count;
}

int __init parport_pc_init (int *io, int *io_hi, int *irq, int *dma)
{
    int count = 0, i = 0;

    if (io && *io) {
        /* Only probe the ports we were given. */
        user_specified = 1;
        do {
            if ((*io_hi) == PARPORT_IOHI_AUTO)
                   *io_hi = 0x400 + *io;
            if (parport_pc_probe_port(*(io++), *(io_hi++),
                          *(irq++), *(dma++), NULL))
                count++;
        } while (*io && (++i < PARPORT_PC_MAX_PORTS));
    } else {
        count += parport_pc_find_ports (irq[0], dma[0]);
    }

    return count;
}

/* Exported symbols. */
EXPORT_SYMBOL (parport_pc_probe_port);
EXPORT_SYMBOL (parport_pc_unregister_port);

#ifdef MODULE
static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
static int io_hi[PARPORT_PC_MAX_PORTS+1] =
    { [0 ... PARPORT_PC_MAX_PORTS] = PARPORT_IOHI_AUTO };
static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_NONE };
static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY };
static const char *irq[PARPORT_PC_MAX_PORTS] = { NULL, };
static const char *dma[PARPORT_PC_MAX_PORTS] = { NULL, };

MODULE_AUTHOR("Phil Blundell, Tim Waugh, others");
MODULE_DESCRIPTION("PC-style parallel port driver");
MODULE_LICENSE("GPL");

MODULE_PARM_DESC(io, "Base I/O address (SPP regs)");
MODULE_PARM(io, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
MODULE_PARM_DESC(io_hi, "Base I/O address (ECR)");
MODULE_PARM(io_hi, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
MODULE_PARM_DESC(irq, "IRQ line");
MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
MODULE_PARM_DESC(dma, "DMA channel");
MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
#if defined(CONFIG_PARPORT_PC_FIFO) || defined(CONFIG_PARPORT_PC_SUPERIO)
MODULE_PARM_DESC(verbose_probing, "Log chit-chat during initialisation");
MODULE_PARM(verbose_probing, "i");
#endif

int init_module(void)
{    
    /* Work out how many ports we have, then get parport_share to parse
       the irq values. */
    unsigned int i;
    int ret;
    for (i = 0; i < PARPORT_PC_MAX_PORTS && io[i]; i++);
    if (i) {
        if (parport_parse_irqs(i, irq, irqval)) return 1;
        if (parport_parse_dmas(i, dma, dmaval)) return 1;
    }
    else {
        /* The user can make us use any IRQs or DMAs we find. */
        int val;

        if (irq[0] && !parport_parse_irqs (1, irq, &val))
            switch (val) {
            case PARPORT_IRQ_NONE:
            case PARPORT_IRQ_AUTO:
                irqval[0] = val;
                break;
            default:
                printk (KERN_WARNING
                    "parport_pc: irq specified "
                    "without base address.  Use 'io=' "
                    "to specify one\n");
            }

        if (dma[0] && !parport_parse_dmas (1, dma, &val))
            switch (val) {
            case PARPORT_DMA_NONE:
            case PARPORT_DMA_AUTO:
                dmaval[0] = val;
                break;
            default:
                printk (KERN_WARNING
                    "parport_pc: dma specified "
                    "without base address.  Use 'io=' "
                    "to specify one\n");
            }
    }

    ret = !parport_pc_init (io, io_hi, irqval, dmaval);
    if (ret && registered_parport)
        pci_unregister_driver (&parport_pc_pci_driver);

    return ret;
}

void cleanup_module(void)
{
    /* We ought to keep track of which ports are actually ours. */
    struct parport *p = parport_enumerate(), *tmp;

    if (!user_specified)
        pci_unregister_driver (&parport_pc_pci_driver);

    while (p) {
        tmp = p->next;
        if (p->modes & PARPORT_MODE_PCSPP)
            parport_pc_unregister_port (p);

        p = tmp;
    }
}
#endif

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ Read-Only ]

:: Make Dir ::
 
[ Read-Only ]
:: Make File ::
 
[ Read-Only ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 1.0 pre-release build #13 powered by Captain Crunch Security Team | http://ccteam.ru | Generation time: 0.0098 ]--