Merge /spare/repo/linux-2.6/
authorJeff Garzik <jgarzik@pobox.com>
Tue, 28 Jun 2005 04:46:46 +0000 (00:46 -0400)
committerJeff Garzik <jgarzik@pobox.com>
Tue, 28 Jun 2005 04:46:46 +0000 (00:46 -0400)
101 files changed:
Documentation/Changes
Documentation/pcmcia/devicetable.txt [new file with mode: 0644]
Documentation/pcmcia/driver-changes.txt [new file with mode: 0644]
arch/sparc64/kernel/auxio.c
arch/sparc64/kernel/entry.S
arch/sparc64/kernel/irq.c
arch/sparc64/kernel/semaphore.c
arch/sparc64/kernel/sparc64_ksyms.c
arch/sparc64/kernel/trampoline.S
arch/sparc64/lib/U1memcpy.S
arch/sparc64/lib/VISsave.S
arch/sparc64/lib/atomic.S
arch/sparc64/lib/bitops.S
arch/sparc64/lib/debuglocks.c
arch/sparc64/lib/dec_and_lock.S
arch/sparc64/lib/rwsem.S
arch/sparc64/mm/init.c
arch/sparc64/mm/ultra.S
drivers/block/cfq-iosched.c
drivers/bluetooth/bluecard_cs.c
drivers/bluetooth/bt3c_cs.c
drivers/bluetooth/btuart_cs.c
drivers/bluetooth/dtl1_cs.c
drivers/char/pcmcia/synclink_cs.c
drivers/ide/Kconfig
drivers/ide/ide-disk.c
drivers/ide/ide-dma.c
drivers/ide/ide-iops.c
drivers/ide/legacy/ide-cs.c
drivers/ide/pci/Makefile
drivers/ide/pci/generic.c
drivers/ide/pci/hpt366.c
drivers/ide/pci/it821x.c [new file with mode: 0644]
drivers/ide/pci/serverworks.c
drivers/input/gameport/gameport.c
drivers/input/serio/serio.c
drivers/isdn/hardware/avm/avm_cs.c
drivers/isdn/hisax/avma1_cs.c
drivers/isdn/hisax/elsa_cs.c
drivers/isdn/hisax/sedlbauer_cs.c
drivers/isdn/hisax/teles_cs.c
drivers/mtd/maps/Kconfig
drivers/mtd/maps/pcmciamtd.c
drivers/net/pcmcia/3c574_cs.c
drivers/net/pcmcia/3c589_cs.c
drivers/net/pcmcia/axnet_cs.c
drivers/net/pcmcia/com20020_cs.c
drivers/net/pcmcia/fmvj18x_cs.c
drivers/net/pcmcia/ibmtr_cs.c
drivers/net/pcmcia/nmclan_cs.c
drivers/net/pcmcia/pcnet_cs.c
drivers/net/pcmcia/smc91c92_cs.c
drivers/net/pcmcia/xirc2ps_cs.c
drivers/net/wireless/airo_cs.c
drivers/net/wireless/atmel_cs.c
drivers/net/wireless/netwave_cs.c
drivers/net/wireless/orinoco_cs.c
drivers/net/wireless/ray_cs.c
drivers/net/wireless/wavelan_cs.c
drivers/net/wireless/wl3501_cs.c
drivers/parport/parport_cs.c
drivers/pcmcia/Kconfig
drivers/pcmcia/Makefile
drivers/pcmcia/cistpl.c
drivers/pcmcia/cs.c
drivers/pcmcia/cs_internal.h
drivers/pcmcia/ds.c
drivers/pcmcia/ds_internal.h [new file with mode: 0644]
drivers/pcmcia/i82365.c
drivers/pcmcia/pcmcia_compat.c
drivers/pcmcia/pcmcia_ioctl.c [new file with mode: 0644]
drivers/pcmcia/pcmcia_resource.c [new file with mode: 0644]
drivers/pcmcia/rsrc_mgr.c
drivers/pcmcia/rsrc_nonstatic.c
drivers/pcmcia/socket_sysfs.c
drivers/pcmcia/yenta_socket.c
drivers/scsi/pcmcia/aha152x_stub.c
drivers/scsi/pcmcia/fdomain_stub.c
drivers/scsi/pcmcia/nsp_cs.c
drivers/scsi/pcmcia/qlogic_stub.c
drivers/scsi/pcmcia/sym53c500_cs.c
drivers/serial/serial_cs.c
drivers/telephony/ixj_pcmcia.c
drivers/usb/host/sl811_cs.c
include/asm-i386/ide.h
include/asm-sparc64/auxio.h
include/asm-sparc64/floppy.h
include/asm-sparc64/irq.h
include/asm-sparc64/rwsem.h
include/asm-sparc64/spinlock.h
include/asm-sparc64/spitfire.h
include/linux/mod_devicetable.h
include/linux/pci_ids.h
include/pcmcia/ciscode.h
include/pcmcia/cs.h
include/pcmcia/device_id.h [new file with mode: 0644]
include/pcmcia/ds.h
include/pcmcia/ss.h
scripts/mod/file2alias.c
sound/pcmcia/pdaudiocf/pdaudiocf.c
sound/pcmcia/vx/vxpocket.c

index b376007..afebdbc 100644 (file)
@@ -44,9 +44,9 @@ running, the suggested command should tell you.
 
 Again, keep in mind that this list assumes you are already
 functionally running a Linux 2.4 kernel.  Also, not all tools are
-necessary on all systems; obviously, if you don't have any PCMCIA (PC
-Card) hardware, for example, you probably needn't concern yourself
-with pcmcia-cs.
+necessary on all systems; obviously, if you don't have any ISDN
+hardware, for example, you probably needn't concern yourself with
+isdn4k-utils.
 
 o  Gnu C                  2.95.3                  # gcc --version
 o  Gnu make               3.79.1                  # make --version
@@ -57,6 +57,7 @@ o  e2fsprogs              1.29                    # tune2fs
 o  jfsutils               1.1.3                   # fsck.jfs -V
 o  reiserfsprogs          3.6.3                   # reiserfsck -V 2>&1|grep reiserfsprogs
 o  xfsprogs               2.6.0                   # xfs_db -V
+o  pcmciautils            001
 o  pcmcia-cs              3.1.21                  # cardmgr -V
 o  quota-tools            3.09                    # quota -V
 o  PPP                    2.4.0                   # pppd --version
@@ -186,13 +187,20 @@ architecture independent and any version from 2.0.0 onward should
 work correctly with this version of the XFS kernel code (2.6.0 or
 later is recommended, due to some significant improvements).
 
+PCMCIAutils
+-----------
+
+PCMCIAutils replaces pcmcia-cs (see below). It properly sets up
+PCMCIA sockets at system startup and loads the appropriate modules
+for 16-bit PCMCIA devices if the kernel is modularized and the hotplug
+subsystem is used.
 
 Pcmcia-cs
 ---------
 
 PCMCIA (PC Card) support is now partially implemented in the main
-kernel source.  Pay attention when you recompile your kernel ;-).
-Also, be sure to upgrade to the latest pcmcia-cs release.
+kernel source. The "pcmciautils" package (see above) replaces pcmcia-cs
+for newest kernels.
 
 Quota-tools
 -----------
@@ -349,9 +357,13 @@ Xfsprogs
 --------
 o  <ftp://oss.sgi.com/projects/xfs/download/>
 
+Pcmciautils
+-----------
+o  <ftp://ftp.kernel.org/pub/linux/utils/kernel/pcmcia/>
+
 Pcmcia-cs
 ---------
-o  <ftp://pcmcia-cs.sourceforge.net/pub/pcmcia-cs/pcmcia-cs-3.1.21.tar.gz>
+o  <http://pcmcia-cs.sourceforge.net/>
 
 Quota-tools
 ----------
diff --git a/Documentation/pcmcia/devicetable.txt b/Documentation/pcmcia/devicetable.txt
new file mode 100644 (file)
index 0000000..045511a
--- /dev/null
@@ -0,0 +1,64 @@
+Matching of PCMCIA devices to drivers is done using one or more of the
+following criteria:
+
+- manufactor ID
+- card ID
+- product ID strings _and_ hashes of these strings
+- function ID
+- device function (actual and pseudo)
+
+You should use the helpers in include/pcmcia/device_id.h for generating the
+struct pcmcia_device_id[] entries which match devices to drivers.
+
+If you want to match product ID strings, you also need to pass the crc32
+hashes of the string to the macro, e.g. if you want to match the product ID
+string 1, you need to use
+
+PCMCIA_DEVICE_PROD_ID1("some_string", 0x(hash_of_some_string)),
+
+If the hash is incorrect, the kernel will inform you about this in "dmesg"
+upon module initialization, and tell you of the correct hash.
+
+You can determine the hash of the product ID strings by running
+"pcmcia-modalias %n.%m" [%n being replaced with the socket number and %m being
+replaced with the device function] from pcmciautils. It generates a string
+in the following form:
+pcmcia:m0149cC1ABf06pfn00fn00pa725B842DpbF1EFEE84pc0877B627pd00000000
+
+The hex value after "pa" is the hash of product ID string 1, after "pb" for
+string 2 and so on.
+
+Alternatively, you can use this small tool to determine the crc32 hash.
+simply pass the string you want to evaluate as argument to this program,
+e.g.
+$ ./crc32hash "Dual Speed"
+
+-------------------------------------------------------------------------
+/* crc32hash.c - derived from linux/lib/crc32.c, GNU GPL v2 */
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+unsigned int crc32(unsigned char const *p, unsigned int len)
+{
+       int i;
+       unsigned int crc = 0;
+       while (len--) {
+               crc ^= *p++;
+               for (i = 0; i < 8; i++)
+                       crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
+       }
+       return crc;
+}
+
+int main(int argc, char **argv) {
+       unsigned int result;
+       if (argc != 2) {
+               printf("no string passed as argument\n");
+               return -1;
+       }
+       result = crc32(argv[1], strlen(argv[1]));
+       printf("0x%x\n", result);
+       return 0;
+}
diff --git a/Documentation/pcmcia/driver-changes.txt b/Documentation/pcmcia/driver-changes.txt
new file mode 100644 (file)
index 0000000..9c315ab
--- /dev/null
@@ -0,0 +1,51 @@
+This file details changes in 2.6 which affect PCMCIA card driver authors:
+
+* in-kernel device<->driver matching
+   PCMCIA devices and their correct drivers can now be matched in
+   kernelspace. See 'devicetable.txt' for details.
+
+* Device model integration (as of 2.6.11)
+   A struct pcmcia_device is registered with the device model core,
+   and can be used (e.g. for SET_NETDEV_DEV) by using
+   handle_to_dev(client_handle_t * handle).
+
+* Convert internal I/O port addresses to unsigned long (as of 2.6.11)
+   ioaddr_t should be replaced by kio_addr_t in PCMCIA card drivers.
+
+* irq_mask and irq_list parameters (as of 2.6.11)
+   The irq_mask and irq_list parameters should no longer be used in
+   PCMCIA card drivers. Instead, it is the job of the PCMCIA core to
+   determine which IRQ should be used. Therefore, link->irq.IRQInfo2
+   is ignored.
+
+* client->PendingEvents is gone (as of 2.6.11)
+   client->PendingEvents is no longer available.
+
+* client->Attributes are gone (as of 2.6.11)
+   client->Attributes is unused, therefore it is removed from all
+   PCMCIA card drivers
+
+* core functions no longer available (as of 2.6.11)
+   The following functions have been removed from the kernel source
+   because they are unused by all in-kernel drivers, and no external
+   driver was reported to rely on them:
+       pcmcia_get_first_region()
+       pcmcia_get_next_region()
+       pcmcia_modify_window()
+       pcmcia_set_event_mask()
+       pcmcia_get_first_window()
+       pcmcia_get_next_window()
+
+* device list iteration upon module removal (as of 2.6.10)
+   It is no longer necessary to iterate on the driver's internal
+   client list and call the ->detach() function upon module removal.
+
+* Resource management. (as of 2.6.8)
+   Although the PCMCIA subsystem will allocate resources for cards,
+   it no longer marks these resources busy. This means that driver
+   authors are now responsible for claiming your resources as per
+   other drivers in Linux. You should use request_region() to mark
+   your IO regions in-use, and request_mem_region() to mark your
+   memory regions in-use. The name argument should be a pointer to
+   your driver name. Eg, for pcnet_cs, name should point to the
+   string "pcnet_cs".
index a0716cc..8852c20 100644 (file)
@@ -16,7 +16,7 @@
 #include <asm/ebus.h>
 #include <asm/auxio.h>
 
-/* This cannot be static, as it is referenced in entry.S */
+/* This cannot be static, as it is referenced in irq.c */
 void __iomem *auxio_register = NULL;
 
 enum auxio_type {
index a47f2d0..eee516a 100644 (file)
@@ -271,8 +271,9 @@ cplus_fptrap_insn_1:
        fmuld           %f0, %f2, %f26
        faddd           %f0, %f2, %f28
        fmuld           %f0, %f2, %f30
+       membar          #Sync
        b,pt            %xcc, fpdis_exit
-        membar         #Sync
+        nop
 2:     andcc           %g5, FPRS_DU, %g0
        bne,pt          %icc, 3f
         fzero          %f32
@@ -301,8 +302,9 @@ cplus_fptrap_insn_2:
        fmuld           %f32, %f34, %f58
        faddd           %f32, %f34, %f60
        fmuld           %f32, %f34, %f62
+       membar          #Sync
        ba,pt           %xcc, fpdis_exit
-        membar         #Sync
+        nop
 3:     mov             SECONDARY_CONTEXT, %g3
        add             %g6, TI_FPREGS, %g1
        ldxa            [%g3] ASI_DMMU, %g5
@@ -699,116 +701,6 @@ utrap_ill:
        ba,pt           %xcc, rtrap
         clr            %l6
 
-#ifdef CONFIG_BLK_DEV_FD
-       .globl          floppy_hardint
-floppy_hardint:
-       wr              %g0, (1 << 11), %clear_softint
-       sethi           %hi(doing_pdma), %g1
-       ld              [%g1 + %lo(doing_pdma)], %g2
-       brz,pn          %g2, floppy_dosoftint
-        sethi          %hi(fdc_status), %g3
-       ldx             [%g3 + %lo(fdc_status)], %g3
-       sethi           %hi(pdma_vaddr), %g5
-       ldx             [%g5 + %lo(pdma_vaddr)], %g4
-       sethi           %hi(pdma_size), %g5
-       ldx             [%g5 + %lo(pdma_size)], %g5
-
-next_byte:
-       lduba           [%g3] ASI_PHYS_BYPASS_EC_E, %g7
-       andcc           %g7, 0x80, %g0
-       be,pn           %icc, floppy_fifo_emptied
-        andcc          %g7, 0x20, %g0
-       be,pn           %icc, floppy_overrun
-        andcc          %g7, 0x40, %g0
-       be,pn           %icc, floppy_write
-        sub            %g5, 1, %g5
-
-       inc             %g3
-       lduba           [%g3] ASI_PHYS_BYPASS_EC_E, %g7
-       dec             %g3
-       orcc            %g0, %g5, %g0
-       stb             %g7, [%g4]
-       bne,pn          %xcc, next_byte
-        add            %g4, 1, %g4
-
-       b,pt            %xcc, floppy_tdone
-        nop
-
-floppy_write:
-       ldub            [%g4], %g7
-       orcc            %g0, %g5, %g0
-       inc             %g3
-       stba            %g7, [%g3] ASI_PHYS_BYPASS_EC_E
-       dec             %g3
-       bne,pn          %xcc, next_byte
-        add            %g4, 1, %g4
-
-floppy_tdone:
-       sethi           %hi(pdma_vaddr), %g1
-       stx             %g4, [%g1 + %lo(pdma_vaddr)]
-       sethi           %hi(pdma_size), %g1
-       stx             %g5, [%g1 + %lo(pdma_size)]
-       sethi           %hi(auxio_register), %g1
-       ldx             [%g1 + %lo(auxio_register)], %g7
-       lduba           [%g7] ASI_PHYS_BYPASS_EC_E, %g5
-       or              %g5, AUXIO_AUX1_FTCNT, %g5
-/*     andn            %g5, AUXIO_AUX1_MASK, %g5 */
-       stba            %g5, [%g7] ASI_PHYS_BYPASS_EC_E
-       andn            %g5, AUXIO_AUX1_FTCNT, %g5
-/*     andn            %g5, AUXIO_AUX1_MASK, %g5 */
-
-       nop; nop;  nop; nop;  nop; nop;
-       nop; nop;  nop; nop;  nop; nop;
-
-       stba            %g5, [%g7] ASI_PHYS_BYPASS_EC_E
-       sethi           %hi(doing_pdma), %g1
-       b,pt            %xcc, floppy_dosoftint
-        st             %g0, [%g1 + %lo(doing_pdma)]
-
-floppy_fifo_emptied:
-       sethi           %hi(pdma_vaddr), %g1
-       stx             %g4, [%g1 + %lo(pdma_vaddr)]
-       sethi           %hi(pdma_size), %g1
-       stx             %g5, [%g1 + %lo(pdma_size)]
-       sethi           %hi(irq_action), %g1
-       or              %g1, %lo(irq_action), %g1
-       ldx             [%g1 + (11 << 3)], %g3          ! irqaction[floppy_irq]
-       ldx             [%g3 + 0x08], %g4               ! action->flags>>48==ino
-       sethi           %hi(ivector_table), %g3
-       srlx            %g4, 48, %g4
-       or              %g3, %lo(ivector_table), %g3
-       sllx            %g4, 5, %g4
-       ldx             [%g3 + %g4], %g4                ! &ivector_table[ino]
-       ldx             [%g4 + 0x10], %g4               ! bucket->iclr
-       stwa            %g0, [%g4] ASI_PHYS_BYPASS_EC_E ! ICLR_IDLE
-       membar          #Sync                           ! probably not needed...
-       retry
-
-floppy_overrun:
-       sethi           %hi(pdma_vaddr), %g1
-       stx             %g4, [%g1 + %lo(pdma_vaddr)]
-       sethi           %hi(pdma_size), %g1
-       stx             %g5, [%g1 + %lo(pdma_size)]
-       sethi           %hi(doing_pdma), %g1
-       st              %g0, [%g1 + %lo(doing_pdma)]
-
-floppy_dosoftint:
-       rdpr            %pil, %g2
-       wrpr            %g0, 15, %pil
-       sethi           %hi(109f), %g7
-       b,pt            %xcc, etrap_irq
-109:    or             %g7, %lo(109b), %g7
-
-       mov             11, %o0
-       mov             0, %o1
-       call            sparc_floppy_irq
-        add            %sp, PTREGS_OFF, %o2
-
-       b,pt            %xcc, rtrap_irq
-        nop
-
-#endif /* CONFIG_BLK_DEV_FD */
-
        /* XXX Here is stuff we still need to write... -DaveM XXX */
        .globl          netbsd_syscall
 netbsd_syscall:
index 4dcb8af..4247125 100644 (file)
@@ -37,6 +37,7 @@
 #include <asm/uaccess.h>
 #include <asm/cache.h>
 #include <asm/cpudata.h>
+#include <asm/auxio.h>
 
 #ifdef CONFIG_SMP
 static void distribute_irqs(void);
@@ -834,137 +835,65 @@ void handler_irq(int irq, struct pt_regs *regs)
 }
 
 #ifdef CONFIG_BLK_DEV_FD
-extern void floppy_interrupt(int irq, void *dev_cookie, struct pt_regs *regs);
+extern irqreturn_t floppy_interrupt(int, void *, struct pt_regs *);;
 
-void sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs)
-{
-       struct irqaction *action = *(irq + irq_action);
-       struct ino_bucket *bucket;
-       int cpu = smp_processor_id();
-
-       irq_enter();
-       kstat_this_cpu.irqs[irq]++;
-
-       *(irq_work(cpu, irq)) = 0;
-       bucket = get_ino_in_irqaction(action) + ivector_table;
-
-       bucket->flags |= IBF_INPROGRESS;
-
-       floppy_interrupt(irq, dev_cookie, regs);
-       upa_writel(ICLR_IDLE, bucket->iclr);
-
-       bucket->flags &= ~IBF_INPROGRESS;
-
-       irq_exit();
-}
-#endif
-
-/* The following assumes that the branch lies before the place we
- * are branching to.  This is the case for a trap vector...
- * You have been warned.
- */
-#define SPARC_BRANCH(dest_addr, inst_addr) \
-          (0x10800000 | ((((dest_addr)-(inst_addr))>>2)&0x3fffff))
-
-#define SPARC_NOP (0x01000000)
+/* XXX No easy way to include asm/floppy.h XXX */
+extern unsigned char *pdma_vaddr;
+extern unsigned long pdma_size;
+extern volatile int doing_pdma;
+extern unsigned long fdc_status;
 
-static void install_fast_irq(unsigned int cpu_irq,
-                            irqreturn_t (*handler)(int, void *, struct pt_regs *))
+irqreturn_t sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs)
 {
-       extern unsigned long sparc64_ttable_tl0;
-       unsigned long ttent = (unsigned long) &sparc64_ttable_tl0;
-       unsigned int *insns;
-
-       ttent += 0x820;
-       ttent += (cpu_irq - 1) << 5;
-       insns = (unsigned int *) ttent;
-       insns[0] = SPARC_BRANCH(((unsigned long) handler),
-                               ((unsigned long)&insns[0]));
-       insns[1] = SPARC_NOP;
-       __asm__ __volatile__("membar #StoreStore; flush %0" : : "r" (ttent));
-}
-
-int request_fast_irq(unsigned int irq,
-                    irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                    unsigned long irqflags, const char *name, void *dev_id)
-{
-       struct irqaction *action;
-       struct ino_bucket *bucket = __bucket(irq);
-       unsigned long flags;
-
-       /* No pil0 dummy buckets allowed here. */
-       if (bucket < &ivector_table[0] ||
-           bucket >= &ivector_table[NUM_IVECS]) {
-               unsigned int *caller;
-
-               __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
-               printk(KERN_CRIT "request_fast_irq: Old style IRQ registry attempt "
-                      "from %p, irq %08x.\n", caller, irq);
-               return -EINVAL;
-       }       
-       
-       if (!handler)
-               return -EINVAL;
+       if (likely(doing_pdma)) {
+               void __iomem *stat = (void __iomem *) fdc_status;
+               unsigned char *vaddr = pdma_vaddr;
+               unsigned long size = pdma_size;
+               u8 val;
+
+               while (size) {
+                       val = readb(stat);
+                       if (unlikely(!(val & 0x80))) {
+                               pdma_vaddr = vaddr;
+                               pdma_size = size;
+                               return IRQ_HANDLED;
+                       }
+                       if (unlikely(!(val & 0x20))) {
+                               pdma_vaddr = vaddr;
+                               pdma_size = size;
+                               doing_pdma = 0;
+                               goto main_interrupt;
+                       }
+                       if (val & 0x40) {
+                               /* read */
+                               *vaddr++ = readb(stat + 1);
+                       } else {
+                               unsigned char data = *vaddr++;
 
-       if ((bucket->pil == 0) || (bucket->pil == 14)) {
-               printk("request_fast_irq: Trying to register shared IRQ 0 or 14.\n");
-               return -EBUSY;
-       }
+                               /* write */
+                               writeb(data, stat + 1);
+                       }
+                       size--;
+               }
 
-       spin_lock_irqsave(&irq_action_lock, flags);
+               pdma_vaddr = vaddr;
+               pdma_size = size;
 
-       action = *(bucket->pil + irq_action);
-       if (action) {
-               if (action->flags & SA_SHIRQ)
-                       panic("Trying to register fast irq when already shared.\n");
-               if (irqflags & SA_SHIRQ)
-                       panic("Trying to register fast irq as shared.\n");
-               printk("request_fast_irq: Trying to register yet already owned.\n");
-               spin_unlock_irqrestore(&irq_action_lock, flags);
-               return -EBUSY;
-       }
+               /* Send Terminal Count pulse to floppy controller. */
+               val = readb(auxio_register);
+               val |= AUXIO_AUX1_FTCNT;
+               writeb(val, auxio_register);
+               val &= AUXIO_AUX1_FTCNT;
+               writeb(val, auxio_register);
 
-       /*
-        * We do not check for SA_SAMPLE_RANDOM in this path. Neither do we
-        * support smp intr affinity in this path.
-        */
-       if (irqflags & SA_STATIC_ALLOC) {
-               if (static_irq_count < MAX_STATIC_ALLOC)
-                       action = &static_irqaction[static_irq_count++];
-               else
-                       printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed "
-                              "using kmalloc\n", bucket->pil, name);
-       }
-       if (action == NULL)
-               action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
-                                                    GFP_ATOMIC);
-       if (!action) {
-               spin_unlock_irqrestore(&irq_action_lock, flags);
-               return -ENOMEM;
+               doing_pdma = 0;
        }
-       install_fast_irq(bucket->pil, handler);
 
-       bucket->irq_info = action;
-       bucket->flags |= IBF_ACTIVE;
-
-       action->handler = handler;
-       action->flags = irqflags;
-       action->dev_id = NULL;
-       action->name = name;
-       action->next = NULL;
-       put_ino_in_irqaction(action, irq);
-       put_smpaff_in_irqaction(action, CPU_MASK_NONE);
-
-       *(bucket->pil + irq_action) = action;
-       enable_irq(irq);
-
-       spin_unlock_irqrestore(&irq_action_lock, flags);
-
-#ifdef CONFIG_SMP
-       distribute_irqs();
-#endif
-       return 0;
+main_interrupt:
+       return floppy_interrupt(irq, dev_cookie, regs);
 }
+EXPORT_SYMBOL(sparc_floppy_irq);
+#endif
 
 /* We really don't need these at all on the Sparc.  We only have
  * stubs here because they are exported to modules.
index 63496c4..a809e63 100644 (file)
@@ -32,8 +32,9 @@ static __inline__ int __sem_update_count(struct semaphore *sem, int incr)
 "      add     %1, %4, %1\n"
 "      cas     [%3], %0, %1\n"
 "      cmp     %0, %1\n"
+"      membar  #StoreLoad | #StoreStore\n"
 "      bne,pn  %%icc, 1b\n"
-"       membar #StoreLoad | #StoreStore\n"
+"       nop\n"
        : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count)
        : "r" (&sem->count), "r" (incr), "m" (sem->count)
        : "cc");
@@ -71,8 +72,9 @@ void up(struct semaphore *sem)
 "      cmp     %%g1, %%g7\n"
 "      bne,pn  %%icc, 1b\n"
 "       addcc  %%g7, 1, %%g0\n"
+"      membar  #StoreLoad | #StoreStore\n"
 "      ble,pn  %%icc, 3f\n"
-"       membar #StoreLoad | #StoreStore\n"
+"       nop\n"
 "2:\n"
 "      .subsection 2\n"
 "3:    mov     %0, %%g1\n"
@@ -128,8 +130,9 @@ void __sched down(struct semaphore *sem)
 "      cmp     %%g1, %%g7\n"
 "      bne,pn  %%icc, 1b\n"
 "       cmp    %%g7, 1\n"
+"      membar  #StoreLoad | #StoreStore\n"
 "      bl,pn   %%icc, 3f\n"
-"       membar #StoreLoad | #StoreStore\n"
+"       nop\n"
 "2:\n"
 "      .subsection 2\n"
 "3:    mov     %0, %%g1\n"
@@ -233,8 +236,9 @@ int __sched down_interruptible(struct semaphore *sem)
 "      cmp     %%g1, %%g7\n"
 "      bne,pn  %%icc, 1b\n"
 "       cmp    %%g7, 1\n"
+"      membar  #StoreLoad | #StoreStore\n"
 "      bl,pn   %%icc, 3f\n"
-"       membar #StoreLoad | #StoreStore\n"
+"       nop\n"
 "2:\n"
 "      .subsection 2\n"
 "3:    mov     %2, %%g1\n"
index e78cc53..56cd96f 100644 (file)
@@ -227,7 +227,6 @@ EXPORT_SYMBOL(__flush_dcache_range);
 
 EXPORT_SYMBOL(mostek_lock);
 EXPORT_SYMBOL(mstk48t02_regs);
-EXPORT_SYMBOL(request_fast_irq);
 #ifdef CONFIG_SUN_AUXIO
 EXPORT_SYMBOL(auxio_set_led);
 EXPORT_SYMBOL(auxio_set_lte);
index 2c8f934..3a145fc 100644 (file)
@@ -98,8 +98,9 @@ startup_continue:
 
        sethi           %hi(prom_entry_lock), %g2
 1:     ldstub          [%g2 + %lo(prom_entry_lock)], %g1
+       membar          #StoreLoad | #StoreStore
        brnz,pn         %g1, 1b
-        membar         #StoreLoad | #StoreStore
+        nop
 
        sethi           %hi(p1275buf), %g2
        or              %g2, %lo(p1275buf), %g2
index da9b520..bafd2fc 100644 (file)
 #define LOOP_CHUNK3(src, dest, len, branch_dest)               \
        MAIN_LOOP_CHUNK(src, dest, f32, f48, len, branch_dest)
 
+#define DO_SYNC                        membar  #Sync;
 #define STORE_SYNC(dest, fsrc)                         \
        EX_ST(STORE_BLK(%fsrc, %dest));                 \
-       add                     %dest, 0x40, %dest;
+       add                     %dest, 0x40, %dest;     \
+       DO_SYNC
 
 #define STORE_JUMP(dest, fsrc, target)                 \
        EX_ST(STORE_BLK(%fsrc, %dest));                 \
        add                     %dest, 0x40, %dest;     \
-       ba,pt                   %xcc, target;
+       ba,pt                   %xcc, target;           \
+        nop;
 
 #define FINISH_VISCHUNK(dest, f0, f1, left)    \
        subcc                   %left, 8, %left;\
@@ -239,17 +242,17 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
        ba,pt           %xcc, 1b+4
         faligndata     %f0, %f2, %f48
 1:     FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0)
-       STORE_JUMP(o0, f48, 40f) membar #Sync
+       STORE_JUMP(o0, f48, 40f)
 2:     FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16)
-       STORE_JUMP(o0, f48, 48f) membar #Sync
+       STORE_JUMP(o0, f48, 48f)
 3:     FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32)
-       STORE_JUMP(o0, f48, 56f) membar #Sync
+       STORE_JUMP(o0, f48, 56f)
 
 1:     FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18)
        LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
@@ -260,17 +263,17 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
        ba,pt           %xcc, 1b+4
         faligndata     %f2, %f4, %f48
 1:     FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2)
-       STORE_JUMP(o0, f48, 41f) membar #Sync
+       STORE_JUMP(o0, f48, 41f)
 2:     FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18)
-       STORE_JUMP(o0, f48, 49f) membar #Sync
+       STORE_JUMP(o0, f48, 49f)
 3:     FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34)
-       STORE_JUMP(o0, f48, 57f) membar #Sync
+       STORE_JUMP(o0, f48, 57f)
 
 1:     FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20)
        LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
@@ -281,17 +284,17 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
        ba,pt           %xcc, 1b+4
         faligndata     %f4, %f6, %f48
 1:     FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4)
-       STORE_JUMP(o0, f48, 42f) membar #Sync
+       STORE_JUMP(o0, f48, 42f)
 2:     FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20)
-       STORE_JUMP(o0, f48, 50f) membar #Sync
+       STORE_JUMP(o0, f48, 50f)
 3:     FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36)
-       STORE_JUMP(o0, f48, 58f) membar #Sync
+       STORE_JUMP(o0, f48, 58f)
 
 1:     FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22)
        LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
@@ -302,17 +305,17 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
        ba,pt           %xcc, 1b+4
         faligndata     %f6, %f8, %f48
 1:     FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6)
-       STORE_JUMP(o0, f48, 43f) membar #Sync
+       STORE_JUMP(o0, f48, 43f)
 2:     FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22)
-       STORE_JUMP(o0, f48, 51f) membar #Sync
+       STORE_JUMP(o0, f48, 51f)
 3:     FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38)
-       STORE_JUMP(o0, f48, 59f) membar #Sync
+       STORE_JUMP(o0, f48, 59f)
 
 1:     FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24)
        LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
@@ -323,17 +326,17 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
        ba,pt           %xcc, 1b+4
         faligndata     %f8, %f10, %f48
 1:     FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8)
-       STORE_JUMP(o0, f48, 44f) membar #Sync
+       STORE_JUMP(o0, f48, 44f)
 2:     FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24)
-       STORE_JUMP(o0, f48, 52f) membar #Sync
+       STORE_JUMP(o0, f48, 52f)
 3:     FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40)
-       STORE_JUMP(o0, f48, 60f) membar #Sync
+       STORE_JUMP(o0, f48, 60f)
 
 1:     FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26)
        LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
@@ -344,17 +347,17 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
        ba,pt           %xcc, 1b+4
         faligndata     %f10, %f12, %f48
 1:     FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10)
-       STORE_JUMP(o0, f48, 45f) membar #Sync
+       STORE_JUMP(o0, f48, 45f)
 2:     FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26)
-       STORE_JUMP(o0, f48, 53f) membar #Sync
+       STORE_JUMP(o0, f48, 53f)
 3:     FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42)
-       STORE_JUMP(o0, f48, 61f) membar #Sync
+       STORE_JUMP(o0, f48, 61f)
 
 1:     FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28)
        LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
@@ -365,17 +368,17 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
        ba,pt           %xcc, 1b+4
         faligndata     %f12, %f14, %f48
 1:     FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12)
-       STORE_JUMP(o0, f48, 46f) membar #Sync
+       STORE_JUMP(o0, f48, 46f)
 2:     FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28)
-       STORE_JUMP(o0, f48, 54f) membar #Sync
+       STORE_JUMP(o0, f48, 54f)
 3:     FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44)
-       STORE_JUMP(o0, f48, 62f) membar #Sync
+       STORE_JUMP(o0, f48, 62f)
 
 1:     FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30)
        LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
@@ -386,17 +389,17 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
        ba,pt           %xcc, 1b+4
         faligndata     %f14, %f16, %f48
 1:     FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14)
-       STORE_JUMP(o0, f48, 47f) membar #Sync
+       STORE_JUMP(o0, f48, 47f)
 2:     FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30)
-       STORE_JUMP(o0, f48, 55f) membar #Sync
+       STORE_JUMP(o0, f48, 55f)
 3:     FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30)
-       STORE_SYNC(o0, f48) membar #Sync
+       STORE_SYNC(o0, f48)
        FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46)
-       STORE_JUMP(o0, f48, 63f) membar #Sync
+       STORE_JUMP(o0, f48, 63f)
 
 40:    FINISH_VISCHUNK(o0, f0,  f2,  g3)
 41:    FINISH_VISCHUNK(o0, f2,  f4,  g3)
index 65e328d..4e18989 100644 (file)
@@ -72,7 +72,11 @@ vis1:        ldub            [%g6 + TI_FPSAVED], %g3
 
        stda            %f48, [%g3 + %g1] ASI_BLK_P
 5:     membar          #Sync
-       jmpl            %g7 + %g0, %g0
+       ba,pt           %xcc, 80f
+        nop
+
+       .align          32
+80:    jmpl            %g7 + %g0, %g0
         nop
 
 6:     ldub            [%g3 + TI_FPSAVED], %o5
@@ -87,8 +91,11 @@ vis1:        ldub            [%g6 + TI_FPSAVED], %g3
        stda            %f32, [%g2 + %g1] ASI_BLK_P
        stda            %f48, [%g3 + %g1] ASI_BLK_P
        membar          #Sync
-       jmpl            %g7 + %g0, %g0
+       ba,pt           %xcc, 80f
+        nop
 
+       .align          32
+80:    jmpl            %g7 + %g0, %g0
         nop
 
        .align          32
@@ -126,6 +133,10 @@ VISenterhalf:
        stda            %f0, [%g2 + %g1] ASI_BLK_P
        stda            %f16, [%g3 + %g1] ASI_BLK_P
        membar          #Sync
+       ba,pt           %xcc, 4f
+        nop
+
+       .align          32
 4:     and             %o5, FPRS_DU, %o5
        jmpl            %g7 + %g0, %g0
         wr             %o5, FPRS_FEF, %fprs
index e528b8d..faf87c3 100644 (file)
@@ -7,18 +7,6 @@
 #include <linux/config.h>
 #include <asm/asi.h>
 
-       /* On SMP we need to use memory barriers to ensure
-        * correct memory operation ordering, nop these out
-        * for uniprocessor.
-        */
-#ifdef CONFIG_SMP
-#define ATOMIC_PRE_BARRIER     membar #StoreLoad | #LoadLoad
-#define ATOMIC_POST_BARRIER    membar #StoreLoad | #StoreStore
-#else
-#define ATOMIC_PRE_BARRIER     nop
-#define ATOMIC_POST_BARRIER    nop
-#endif
-
        .text
 
        /* Two versions of the atomic routines, one that
@@ -52,6 +40,24 @@ atomic_sub: /* %o0 = decrement, %o1 = atomic_ptr */
         nop
        .size   atomic_sub, .-atomic_sub
 
+       /* On SMP we need to use memory barriers to ensure
+        * correct memory operation ordering, nop these out
+        * for uniprocessor.
+        */
+#ifdef CONFIG_SMP
+
+#define ATOMIC_PRE_BARRIER     membar #StoreLoad | #LoadLoad;
+#define ATOMIC_POST_BARRIER    \
+       ba,pt %xcc, 80b;        \
+       membar #StoreLoad | #StoreStore
+
+80:    retl
+        nop
+#else
+#define ATOMIC_PRE_BARRIER
+#define ATOMIC_POST_BARRIER
+#endif
+
        .globl  atomic_add_ret
        .type   atomic_add_ret,#function
 atomic_add_ret: /* %o0 = increment, %o1 = atomic_ptr */
@@ -62,9 +68,10 @@ atomic_add_ret: /* %o0 = increment, %o1 = atomic_ptr */
        cmp     %g1, %g7
        bne,pn  %icc, 1b
         add    %g7, %o0, %g7
+       sra     %g7, 0, %o0
        ATOMIC_POST_BARRIER
        retl
-        sra    %g7, 0, %o0
+        nop
        .size   atomic_add_ret, .-atomic_add_ret
 
        .globl  atomic_sub_ret
@@ -77,9 +84,10 @@ atomic_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */
        cmp     %g1, %g7
        bne,pn  %icc, 1b
         sub    %g7, %o0, %g7
+       sra     %g7, 0, %o0
        ATOMIC_POST_BARRIER
        retl
-        sra    %g7, 0, %o0
+        nop
        .size   atomic_sub_ret, .-atomic_sub_ret
 
        .globl  atomic64_add
@@ -118,9 +126,10 @@ atomic64_add_ret: /* %o0 = increment, %o1 = atomic_ptr */
        cmp     %g1, %g7
        bne,pn  %xcc, 1b
         add    %g7, %o0, %g7
+       mov     %g7, %o0
        ATOMIC_POST_BARRIER
        retl
-        mov    %g7, %o0
+        nop
        .size   atomic64_add_ret, .-atomic64_add_ret
 
        .globl  atomic64_sub_ret
@@ -133,7 +142,8 @@ atomic64_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */
        cmp     %g1, %g7
        bne,pn  %xcc, 1b
         sub    %g7, %o0, %g7
+       mov     %g7, %o0
        ATOMIC_POST_BARRIER
        retl
-        mov    %g7, %o0
+        nop
        .size   atomic64_sub_ret, .-atomic64_sub_ret
index 886dcd2..31afbfe 100644 (file)
@@ -7,20 +7,26 @@
 #include <linux/config.h>
 #include <asm/asi.h>
 
+       .text
+
        /* On SMP we need to use memory barriers to ensure
         * correct memory operation ordering, nop these out
         * for uniprocessor.
         */
+
 #ifdef CONFIG_SMP
 #define BITOP_PRE_BARRIER      membar #StoreLoad | #LoadLoad
-#define BITOP_POST_BARRIER     membar #StoreLoad | #StoreStore
+#define BITOP_POST_BARRIER     \
+       ba,pt   %xcc, 80b;      \
+       membar #StoreLoad | #StoreStore
+
+80:    retl
+        nop
 #else
-#define BITOP_PRE_BARRIER      nop
-#define BITOP_POST_BARRIER     nop
+#define BITOP_PRE_BARRIER
+#define BITOP_POST_BARRIER
 #endif
 
-       .text
-
        .globl  test_and_set_bit
        .type   test_and_set_bit,#function
 test_and_set_bit:      /* %o0=nr, %o1=addr */
@@ -37,10 +43,11 @@ test_and_set_bit:   /* %o0=nr, %o1=addr */
        cmp     %g7, %g1
        bne,pn  %xcc, 1b
         and    %g7, %o2, %g2
-       BITOP_POST_BARRIER
        clr     %o0
+       movrne  %g2, 1, %o0
+       BITOP_POST_BARRIER
        retl
-        movrne %g2, 1, %o0
+        nop
        .size   test_and_set_bit, .-test_and_set_bit
 
        .globl  test_and_clear_bit
@@ -59,10 +66,11 @@ test_and_clear_bit: /* %o0=nr, %o1=addr */
        cmp     %g7, %g1
        bne,pn  %xcc, 1b
         and    %g7, %o2, %g2
-       BITOP_POST_BARRIER
        clr     %o0
+       movrne  %g2, 1, %o0
+       BITOP_POST_BARRIER
        retl
-        movrne %g2, 1, %o0
+        nop
        .size   test_and_clear_bit, .-test_and_clear_bit
 
        .globl  test_and_change_bit
@@ -81,10 +89,11 @@ test_and_change_bit:        /* %o0=nr, %o1=addr */
        cmp     %g7, %g1
        bne,pn  %xcc, 1b
         and    %g7, %o2, %g2
-       BITOP_POST_BARRIER
        clr     %o0
+       movrne  %g2, 1, %o0
+       BITOP_POST_BARRIER
        retl
-        movrne %g2, 1, %o0
+        nop
        .size   test_and_change_bit, .-test_and_change_bit
 
        .globl  set_bit
index c421e0c..f03344c 100644 (file)
@@ -252,8 +252,9 @@ wlock_again:
 "              andn    %%g1, %%g3, %%g7\n"
 "              casx    [%0], %%g1, %%g7\n"
 "              cmp     %%g1, %%g7\n"
+"              membar  #StoreLoad | #StoreStore\n"
 "              bne,pn  %%xcc, 1b\n"
-"               membar #StoreLoad | #StoreStore"
+"               nop"
                : /* no outputs */
                : "r" (&(rw->lock))
                : "g3", "g1", "g7", "cc", "memory");
@@ -351,8 +352,9 @@ int _do_write_trylock (rwlock_t *rw, char *str)
 "              andn    %%g1, %%g3, %%g7\n"
 "              casx    [%0], %%g1, %%g7\n"
 "              cmp     %%g1, %%g7\n"
+"              membar  #StoreLoad | #StoreStore\n"
 "              bne,pn  %%xcc, 1b\n"
-"               membar #StoreLoad | #StoreStore"
+"               nop"
                : /* no outputs */
                : "r" (&(rw->lock))
                : "g3", "g1", "g7", "cc", "memory");
index 7e6fdae..8ee288d 100644 (file)
@@ -48,8 +48,9 @@ start_to_zero:
 #endif
 to_zero:
        ldstub  [%o1], %g3
+       membar  #StoreLoad | #StoreStore
        brnz,pn %g3, spin_on_lock
-        membar #StoreLoad | #StoreStore
+        nop
 loop2: cas     [%o0], %g2, %g7         /* ASSERT(g7 == 0) */
        cmp     %g2, %g7
 
@@ -71,8 +72,9 @@ loop2:        cas     [%o0], %g2, %g7         /* ASSERT(g7 == 0) */
         nop
 spin_on_lock:
        ldub    [%o1], %g3
+       membar  #LoadLoad
        brnz,pt %g3, spin_on_lock
-        membar #LoadLoad
+        nop
        ba,pt   %xcc, to_zero
         nop
        nop
index 174ff7b..75f0e6b 100644 (file)
@@ -17,8 +17,9 @@ __down_read:
        bne,pn          %icc, 1b
         add            %g7, 1, %g7
        cmp             %g7, 0
+       membar          #StoreLoad | #StoreStore
        bl,pn           %icc, 3f
-        membar         #StoreLoad | #StoreStore
+        nop
 2:
        retl
         nop
@@ -57,8 +58,9 @@ __down_write:
        cmp             %g3, %g7
        bne,pn          %icc, 1b
         cmp            %g7, 0
+       membar          #StoreLoad | #StoreStore
        bne,pn          %icc, 3f
-        membar         #StoreLoad | #StoreStore
+        nop
 2:     retl
         nop
 3:
@@ -97,8 +99,9 @@ __up_read:
        cmp             %g1, %g7
        bne,pn          %icc, 1b
         cmp            %g7, 0
+       membar          #StoreLoad | #StoreStore
        bl,pn           %icc, 3f
-        membar         #StoreLoad | #StoreStore
+        nop
 2:     retl
         nop
 3:     sethi           %hi(RWSEM_ACTIVE_MASK), %g1
@@ -126,8 +129,9 @@ __up_write:
        bne,pn          %icc, 1b
         sub            %g7, %g1, %g7
        cmp             %g7, 0
+       membar          #StoreLoad | #StoreStore
        bl,pn           %icc, 3f
-        membar         #StoreLoad | #StoreStore
+        nop
 2:
        retl
         nop
@@ -151,8 +155,9 @@ __downgrade_write:
        bne,pn          %icc, 1b
         sub            %g7, %g1, %g7
        cmp             %g7, 0
+       membar          #StoreLoad | #StoreStore
        bl,pn           %icc, 3f
-        membar         #StoreLoad | #StoreStore
+        nop
 2:
        retl
         nop
index 9c52220..8fc413c 100644 (file)
@@ -136,8 +136,9 @@ static __inline__ void set_dcache_dirty(struct page *page, int this_cpu)
                             "or        %%g1, %0, %%g1\n\t"
                             "casx      [%2], %%g7, %%g1\n\t"
                             "cmp       %%g7, %%g1\n\t"
+                            "membar    #StoreLoad | #StoreStore\n\t"
                             "bne,pn    %%xcc, 1b\n\t"
-                            " membar   #StoreLoad | #StoreStore"
+                            " nop"
                             : /* no outputs */
                             : "r" (mask), "r" (non_cpu_bits), "r" (&page->flags)
                             : "g1", "g7");
@@ -157,8 +158,9 @@ static __inline__ void clear_dcache_dirty_cpu(struct page *page, unsigned long c
                             " andn     %%g7, %1, %%g1\n\t"
                             "casx      [%2], %%g7, %%g1\n\t"
                             "cmp       %%g7, %%g1\n\t"
+                            "membar    #StoreLoad | #StoreStore\n\t"
                             "bne,pn    %%xcc, 1b\n\t"
-                            " membar   #StoreLoad | #StoreStore\n"
+                            " nop\n"
                             "2:"
                             : /* no outputs */
                             : "r" (cpu), "r" (mask), "r" (&page->flags),
index 7a09343..7a2431d 100644 (file)
@@ -266,8 +266,9 @@ __cheetah_flush_tlb_pending:        /* 22 insns */
         andn           %o3, 1, %o3
        stxa            %g0, [%o3] ASI_IMMU_DEMAP
 2:     stxa            %g0, [%o3] ASI_DMMU_DEMAP       
+       membar          #Sync
        brnz,pt         %o1, 1b
-        membar         #Sync
+        nop
        stxa            %g2, [%o4] ASI_DMMU
        flush           %g6
        wrpr            %g0, 0, %tl
index ff1cc96..de5746e 100644 (file)
@@ -300,7 +300,6 @@ CFQ_CRQ_FNS(requeued);
 static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned int, unsigned short);
 static void cfq_dispatch_sort(request_queue_t *, struct cfq_rq *);
 static void cfq_put_cfqd(struct cfq_data *cfqd);
-static inline int cfq_pending_requests(struct cfq_data *cfqd);
 
 #define process_sync(tsk)      ((tsk)->flags & PF_SYNCWRITE)
 
@@ -348,6 +347,28 @@ static struct request *cfq_find_rq_hash(struct cfq_data *cfqd, sector_t offset)
        return NULL;
 }
 
+static inline int cfq_pending_requests(struct cfq_data *cfqd)
+{
+       return !list_empty(&cfqd->queue->queue_head) || cfqd->busy_queues;
+}
+
+/*
+ * scheduler run of queue, if there are requests pending and no one in the
+ * driver that will restart queueing
+ */
+static inline void cfq_schedule_dispatch(struct cfq_data *cfqd)
+{
+       if (!cfqd->rq_in_driver && cfq_pending_requests(cfqd))
+               kblockd_schedule_work(&cfqd->unplug_work);
+}
+
+static int cfq_queue_empty(request_queue_t *q)
+{
+       struct cfq_data *cfqd = q->elevator->elevator_data;
+
+       return !cfq_pending_requests(cfqd);
+}
+
 /*
  * Lifted from AS - choose which of crq1 and crq2 that is best served now.
  * We choose the request that is closest to the head right now. Distance
@@ -1071,16 +1092,6 @@ cfq_prio_to_maxrq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
        return 2 * (base_rq + base_rq * (CFQ_PRIO_LISTS - 1 - cfqq->ioprio));
 }
 
-/*
- * scheduler run of queue, if there are requests pending and no one in the
- * driver that will restart queueing
- */
-static inline void cfq_schedule_dispatch(struct cfq_data *cfqd)
-{
-       if (!cfqd->rq_in_driver && cfq_pending_requests(cfqd))
-               kblockd_schedule_work(&cfqd->unplug_work);
-}
-
 /*
  * get next queue for service
  */
@@ -1846,18 +1857,6 @@ cfq_insert_request(request_queue_t *q, struct request *rq, int where)
        }
 }
 
-static inline int cfq_pending_requests(struct cfq_data *cfqd)
-{
-       return !list_empty(&cfqd->queue->queue_head) || cfqd->busy_queues;
-}
-
-static int cfq_queue_empty(request_queue_t *q)
-{
-       struct cfq_data *cfqd = q->elevator->elevator_data;
-
-       return !cfq_pending_requests(cfqd);
-}
-
 static void cfq_completed_request(request_queue_t *q, struct request *rq)
 {
        struct cfq_rq *crq = RQ_DATA(rq);
@@ -1952,7 +1951,7 @@ __cfq_may_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq,
 {
 #if 1
        if ((cfq_cfqq_wait_request(cfqq) || cfq_cfqq_must_alloc(cfqq)) &&
-           !cfq_cfqq_must_alloc_slice) {
+           !cfq_cfqq_must_alloc_slice(cfqq)) {
                cfq_mark_cfqq_must_alloc_slice(cfqq);
                return ELV_MQUEUE_MUST;
        }
@@ -1969,7 +1968,7 @@ __cfq_may_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                 * only allow 1 ELV_MQUEUE_MUST per slice, otherwise we
                 * can quickly flood the queue with writes from a single task
                 */
-               if (rw == READ || !cfq_cfqq_must_alloc_slice) {
+               if (rw == READ || !cfq_cfqq_must_alloc_slice(cfqq)) {
                        cfq_mark_cfqq_must_alloc_slice(cfqq);
                        return ELV_MQUEUE_MUST;
                }
index e481cc4..5ef9adb 100644 (file)
@@ -1089,6 +1089,14 @@ static int bluecard_event(event_t event, int priority, event_callback_args_t *ar
        return 0;
 }
 
+static struct pcmcia_device_id bluecard_ids[] = {
+       PCMCIA_DEVICE_PROD_ID12("BlueCard", "LSE041", 0xbaf16fbf, 0x657cc15e),
+       PCMCIA_DEVICE_PROD_ID12("BTCFCARD", "LSE139", 0xe3987764, 0x2524b59c),
+       PCMCIA_DEVICE_PROD_ID12("WSS", "LSE039", 0x0a0736ec, 0x24e6dfab),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, bluecard_ids);
+
 static struct pcmcia_driver bluecard_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -1096,6 +1104,7 @@ static struct pcmcia_driver bluecard_driver = {
        },
        .attach         = bluecard_attach,
        .detach         = bluecard_detach,
+       .id_table       = bluecard_ids,
 };
 
 static int __init init_bluecard_cs(void)
index f71e5c7..9013cd7 100644 (file)
@@ -935,6 +935,12 @@ static int bt3c_event(event_t event, int priority, event_callback_args_t *args)
        return 0;
 }
 
+static struct pcmcia_device_id bt3c_ids[] = {
+       PCMCIA_DEVICE_PROD_ID13("3COM", "Bluetooth PC Card", 0xefce0a31, 0xd4ce9b02),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, bt3c_ids);
+
 static struct pcmcia_driver bt3c_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -942,6 +948,7 @@ static struct pcmcia_driver bt3c_driver = {
        },
        .attach         = bt3c_attach,
        .detach         = bt3c_detach,
+       .id_table       = bt3c_ids,
 };
 
 static int __init init_bt3c_cs(void)
index ad8d972..c479484 100644 (file)
@@ -855,6 +855,12 @@ static int btuart_event(event_t event, int priority, event_callback_args_t *args
        return 0;
 }
 
+static struct pcmcia_device_id btuart_ids[] = {
+       /* don't use this driver. Use serial_cs + hci_uart instead */
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, btuart_ids);
+
 static struct pcmcia_driver btuart_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -862,6 +868,7 @@ static struct pcmcia_driver btuart_driver = {
        },
        .attach         = btuart_attach,
        .detach         = btuart_detach,
+       .id_table       = btuart_ids,
 };
 
 static int __init init_btuart_cs(void)
index fe954e5..bb12f7d 100644 (file)
@@ -807,6 +807,13 @@ static int dtl1_event(event_t event, int priority, event_callback_args_t *args)
        return 0;
 }
 
+static struct pcmcia_device_id dtl1_ids[] = {
+       PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-1", 0xe1bfdd64, 0xe168480d),
+       PCMCIA_DEVICE_PROD_ID12("Socket", "CF", 0xb38bcc2e, 0x44ebf863),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, dtl1_ids);
+
 static struct pcmcia_driver dtl1_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -814,6 +821,7 @@ static struct pcmcia_driver dtl1_driver = {
        },
        .attach         = dtl1_attach,
        .detach         = dtl1_detach,
+       .id_table       = dtl1_ids,
 };
 
 static int __init init_dtl1_cs(void)
index 1c8d866..8f36b17 100644 (file)
@@ -581,7 +581,7 @@ static dev_link_t *mgslpc_attach(void)
 
     /* Interrupt setup */
     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
-    link->irq.IRQInfo1   = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
+    link->irq.IRQInfo1   = IRQ_LEVEL_ID;
     link->irq.Handler = NULL;
     
     link->conf.Attributes = 0;
@@ -3081,6 +3081,12 @@ void mgslpc_remove_device(MGSLPC_INFO *remove_info)
        }
 }
 
+static struct pcmcia_device_id mgslpc_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(0x02c5, 0x0050),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, mgslpc_ids);
+
 static struct pcmcia_driver mgslpc_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -3088,6 +3094,7 @@ static struct pcmcia_driver mgslpc_driver = {
        },
        .attach         = mgslpc_attach,
        .detach         = mgslpc_detach,
+       .id_table       = mgslpc_ids,
 };
 
 static struct tty_operations mgslpc_ops = {
index 0273f12..5f33df4 100644 (file)
@@ -606,6 +606,12 @@ config BLK_DEV_IT8172
          <http://www.ite.com.tw/ia/brief_it8172bsp.htm>; picture of the
          board at <http://www.mvista.com/partners/semiconductor/ite.html>.
 
+config BLK_DEV_IT821X
+       tristate "IT821X IDE support"
+       help
+         This driver adds support for the ITE 8211 IDE controller and the
+         IT 8212 IDE RAID controller in both RAID and pass-through mode.
+
 config BLK_DEV_NS87415
        tristate "NS87415 chipset support"
        help
index d6f9348..f9c1acb 100644 (file)
@@ -119,6 +119,10 @@ static int lba_capacity_is_ok (struct hd_driveid *id)
 {
        unsigned long lba_sects, chs_sects, head, tail;
 
+       /* No non-LBA info .. so valid! */
+       if (id->cyls == 0)
+               return 1;
+
        /*
         * The ATA spec tells large drives to return
         * C/H/S = 16383/16/63 independent of their size.
index 2d2eefb..1e15313 100644 (file)
@@ -132,7 +132,6 @@ static const struct drive_list_entry drive_blacklist [] = {
        { "SAMSUNG CD-ROM SC-148C",     "ALL"           },
        { "SAMSUNG CD-ROM SC",  "ALL"           },
        { "SanDisk SDP3B-64"    ,       "ALL"           },
-       { "SAMSUNG CD-ROM SN-124",      "ALL"           },
        { "ATAPI CD-ROM DRIVE 40X MAXIMUM",     "ALL"           },
        { "_NEC DV5800A",               "ALL"           },  
        { NULL                  ,       NULL            }
index 5302494..b443b04 100644 (file)
@@ -1181,7 +1181,8 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
                pre_reset(drive);
                SELECT_DRIVE(drive);
                udelay (20);
-               hwif->OUTB(WIN_SRST, IDE_COMMAND_REG);
+               hwif->OUTBSYNC(drive, WIN_SRST, IDE_COMMAND_REG);
+               ndelay(400);
                hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
                hwgroup->polling = 1;
                __ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
index e20327e..978d27d 100644 (file)
@@ -457,6 +457,40 @@ int ide_event(event_t event, int priority,
     return 0;
 } /* ide_event */
 
+static struct pcmcia_device_id ide_ids[] = {
+       PCMCIA_DEVICE_FUNC_ID(4),
+       PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704),
+       PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d),
+       PCMCIA_DEVICE_MANF_CARD(0x2080, 0x0001),
+       PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401),
+       PCMCIA_DEVICE_PROD_ID123("Caravelle", "PSC-IDE ", "PSC000", 0x8c36137c, 0xd0693ab8, 0x2768a9f0),
+       PCMCIA_DEVICE_PROD_ID123("CDROM", "IDE", "MCD-601p", 0x1b9179ca, 0xede88951, 0x0d902f74),
+       PCMCIA_DEVICE_PROD_ID123("PCMCIA", "IDE CARD", "F1", 0x281f1c5d, 0x1907960c, 0xf7fde8b9),
+       PCMCIA_DEVICE_PROD_ID12("ARGOSY", "CD-ROM", 0x78f308dc, 0x66536591),
+       PCMCIA_DEVICE_PROD_ID12("ARGOSY", "PnPIDE", 0x78f308dc, 0x0c694728),
+       PCMCIA_DEVICE_PROD_ID12("CNF CD-M", "CD-ROM", 0x7d93b852, 0x66536591),
+       PCMCIA_DEVICE_PROD_ID12("Creative Technology Ltd.", "PCMCIA CD-ROM Interface Card", 0xff8c8a45, 0xfe8020c4),
+       PCMCIA_DEVICE_PROD_ID12("Digital Equipment Corporation.", "Digital Mobile Media CD-ROM", 0x17692a66, 0xef1dcbde),
+       PCMCIA_DEVICE_PROD_ID12("EXP", "CD", 0x6f58c983, 0xaae5994f),
+       PCMCIA_DEVICE_PROD_ID12("EXP   ", "CD-ROM", 0x0a5c52fd, 0x66536591),
+       PCMCIA_DEVICE_PROD_ID12("EXP   ", "PnPIDE", 0x0a5c52fd, 0x0c694728),
+       PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e),
+       PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
+       PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2      ", 0x547e66dc, 0x8671043b),
+       PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149),
+       PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674),
+       PCMCIA_DEVICE_PROD_ID12("LOOKMEET", "CBIDE2      ", 0xe37be2b5, 0x8671043b),
+       PCMCIA_DEVICE_PROD_ID12(" ", "NinjaATA-", 0x3b6e20c8, 0xebe0bd79),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "CD-ROM", 0x281f1c5d, 0x66536591),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "PnPIDE", 0x281f1c5d, 0x0c694728),
+       PCMCIA_DEVICE_PROD_ID12("SHUTTLE TECHNOLOGY LTD.", "PCCARD-IDE/ATAPI Adapter", 0x4a3f0ba0, 0x322560e1),
+       PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003),
+       PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852),
+       PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, ide_ids);
+
 static struct pcmcia_driver ide_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -464,6 +498,7 @@ static struct pcmcia_driver ide_cs_driver = {
        },
        .attach         = ide_attach,
        .detach         = ide_detach,
+       .id_table       = ide_ids,
 };
 
 static int __init init_ide_cs(void)
index 55e6e55..af46226 100644 (file)
@@ -12,6 +12,7 @@ obj-$(CONFIG_BLK_DEV_HPT34X)          += hpt34x.o
 obj-$(CONFIG_BLK_DEV_HPT366)           += hpt366.o
 #obj-$(CONFIG_BLK_DEV_HPT37X)          += hpt37x.o
 obj-$(CONFIG_BLK_DEV_IT8172)           += it8172.o
+obj-$(CONFIG_BLK_DEV_IT821X)           += it821x.o
 obj-$(CONFIG_BLK_DEV_NS87415)          += ns87415.o
 obj-$(CONFIG_BLK_DEV_OPTI621)          += opti621.o
 obj-$(CONFIG_BLK_DEV_PDC202XX_OLD)     += pdc202xx_old.o
index 4565cc3..da46577 100644 (file)
 
 #include <asm/io.h>
 
+static int ide_generic_all;            /* Set to claim all devices */
+
+static int __init ide_generic_all_on(char *unused)
+{
+       ide_generic_all = 1;
+       printk(KERN_INFO "IDE generic will claim all unknown PCI IDE storage controllers.\n");
+       return 1;
+}
+
+__setup("all-generic-ide", ide_generic_all_on);
+
 static void __devinit init_hwif_generic (ide_hwif_t *hwif)
 {
        switch(hwif->pci_dev->device) {
@@ -78,79 +89,85 @@ static void __devinit init_hwif_generic (ide_hwif_t *hwif)
 
 static ide_pci_device_t generic_chipsets[] __devinitdata = {
        {       /* 0 */
+               .name           = "Unknown",
+               .init_hwif      = init_hwif_generic,
+               .channels       = 2,
+               .autodma        = AUTODMA,
+               .bootable       = ON_BOARD,
+       },{     /* 1 */
                .name           = "NS87410",
                .init_hwif      = init_hwif_generic,
                .channels       = 2,
                .autodma        = AUTODMA,
                .enablebits     = {{0x43,0x08,0x08}, {0x47,0x08,0x08}},
                .bootable       = ON_BOARD,
-        },{    /* 1 */
+        },{    /* 2 */
                .name           = "SAMURAI",
                .init_hwif      = init_hwif_generic,
                .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = ON_BOARD,
-       },{     /* 2 */
+       },{     /* 3 */
                .name           = "HT6565",
                .init_hwif      = init_hwif_generic,
                .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = ON_BOARD,
-       },{     /* 3 */
+       },{     /* 4 */
                .name           = "UM8673F",
                .init_hwif      = init_hwif_generic,
                .channels       = 2,
                .autodma        = NODMA,
                .bootable       = ON_BOARD,
-       },{     /* 4 */
+       },{     /* 5 */
                .name           = "UM8886A",
                .init_hwif      = init_hwif_generic,
                .channels       = 2,
                .autodma        = NODMA,
                .bootable       = ON_BOARD,
-       },{     /* 5 */
+       },{     /* 6 */
                .name           = "UM8886BF",
                .init_hwif      = init_hwif_generic,
                .channels       = 2,
                .autodma        = NODMA,
                .bootable       = ON_BOARD,
-       },{     /* 6 */
+       },{     /* 7 */
                .name           = "HINT_IDE",
                .init_hwif      = init_hwif_generic,
                .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = ON_BOARD,
-       },{     /* 7 */
+       },{     /* 8 */
                .name           = "VIA_IDE",
                .init_hwif      = init_hwif_generic,
                .channels       = 2,
                .autodma        = NOAUTODMA,
                .bootable       = ON_BOARD,
-       },{     /* 8 */
+       },{     /* 9 */
                .name           = "OPTI621V",
                .init_hwif      = init_hwif_generic,
                .channels       = 2,
                .autodma        = NOAUTODMA,
                .bootable       = ON_BOARD,
-       },{     /* 9 */
+       },{     /* 10 */
                .name           = "VIA8237SATA",
                .init_hwif      = init_hwif_generic,
                .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
-       },{     /* 10 */
+       },{     /* 11 */
                .name           = "Piccolo0102",
                .init_hwif      = init_hwif_generic,
                .channels       = 2,
                .autodma        = NOAUTODMA,
                .bootable       = ON_BOARD,
-       },{     /* 11 */
+       },{     /* 12 */
                .name           = "Piccolo0103",
                .init_hwif      = init_hwif_generic,
                .channels       = 2,
                .autodma        = NOAUTODMA,
                .bootable       = ON_BOARD,
-       },{     /* 12 */
+       },{     /* 13 */
                .name           = "Piccolo0105",
                .init_hwif      = init_hwif_generic,
                .channels       = 2,
@@ -174,6 +191,10 @@ static int __devinit generic_init_one(struct pci_dev *dev, const struct pci_devi
        u16 command;
        int ret = -ENODEV;
 
+       /* Don't use the generic entry unless instructed to do so */
+       if (id->driver_data == 0 && ide_generic_all == 0)
+                       goto out;
+
        if (dev->vendor == PCI_VENDOR_ID_UMC &&
            dev->device == PCI_DEVICE_ID_UMC_UM8886A &&
            (!(PCI_FUNC(dev->devfn) & 1)))
@@ -195,21 +216,23 @@ out:
 }
 
 static struct pci_device_id generic_pci_tbl[] = {
-       { PCI_VENDOR_ID_NS,     PCI_DEVICE_ID_NS_87410,            PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       { PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
-       { PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
-       { PCI_VENDOR_ID_UMC,    PCI_DEVICE_ID_UMC_UM8673F,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
-       { PCI_VENDOR_ID_UMC,    PCI_DEVICE_ID_UMC_UM8886A,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
-       { PCI_VENDOR_ID_UMC,    PCI_DEVICE_ID_UMC_UM8886BF,        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
-       { PCI_VENDOR_ID_HINT,   PCI_DEVICE_ID_HINT_VXPROII_IDE,    PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
-       { PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_82C561,          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7},
-       { PCI_VENDOR_ID_OPTI,   PCI_DEVICE_ID_OPTI_82C558,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8},
+       { PCI_VENDOR_ID_NS,     PCI_DEVICE_ID_NS_87410,            PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+       { PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+       { PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+       { PCI_VENDOR_ID_UMC,    PCI_DEVICE_ID_UMC_UM8673F,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+       { PCI_VENDOR_ID_UMC,    PCI_DEVICE_ID_UMC_UM8886A,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+       { PCI_VENDOR_ID_UMC,    PCI_DEVICE_ID_UMC_UM8886BF,        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
+       { PCI_VENDOR_ID_HINT,   PCI_DEVICE_ID_HINT_VXPROII_IDE,    PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7},
+       { PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_82C561,          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8},
+       { PCI_VENDOR_ID_OPTI,   PCI_DEVICE_ID_OPTI_82C558,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9},
 #ifdef CONFIG_BLK_DEV_IDE_SATA
-       { PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_8237_SATA,       PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9},
+       { PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_8237_SATA,       PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10},
 #endif
-       { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO,     PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10},
-       { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11},
-       { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12},
+       { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO,     PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11},
+       { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12},
+       { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13},
+       /* Must come last. If you add entries adjust this table appropriately and the init_one code */
+       { PCI_ANY_ID,           PCI_ANY_ID,                        PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 0},
        { 0, },
 };
 MODULE_DEVICE_TABLE(pci, generic_pci_tbl);
index c8ee0b8..7b64db1 100644 (file)
  * donation of an ABit BP6 mainboard, processor, and memory acellerated
  * development and support.
  *
+ *
+ * Highpoint have their own driver (source except for the raid part)
+ * available from http://www.highpoint-tech.com/hpt3xx-opensource-v131.tgz
+ * This may be useful to anyone wanting to work on the mainstream hpt IDE.
+ *
  * Note that final HPT370 support was done by force extraction of GPL.
  *
  * - add function for getting/setting power status of drive
@@ -446,44 +451,29 @@ static struct chipset_bus_clock_list_entry sixty_six_base_hpt374[] = {
 #define F_LOW_PCI_50   0x2d
 #define F_LOW_PCI_66   0x42
 
-/* FIXME: compare with driver's code before removing */
-#if 0
-               if (hpt_minimum_revision(dev, 3)) {
-                       u8 cbl;
-                       cbl = inb(iobase + 0x7b);
-                       outb(cbl | 1, iobase + 0x7b);
-                       outb(cbl & ~1, iobase + 0x7b);
-                       cbl = inb(iobase + 0x7a);
-                       p += sprintf(p, "Cable:          ATA-%d"
-                                       "                          ATA-%d\n",
-                               (cbl & 0x02) ? 33 : 66,
-                               (cbl & 0x01) ? 33 : 66);
-                       p += sprintf(p, "\n");
-               }
-               {
-                       u8 c2, c3;
-                       /* older revs don't have these registers mapped 
-                        * into io space */
-                       pci_read_config_byte(dev, 0x43, &c0);
-                       pci_read_config_byte(dev, 0x47, &c1);
-                       pci_read_config_byte(dev, 0x4b, &c2);
-                       pci_read_config_byte(dev, 0x4f, &c3);
-
-                       p += sprintf(p, "Mode:           %s             %s"
-                                       "           %s              %s\n",
-                               (c0 & 0x10) ? "UDMA" : (c0 & 0x20) ? "DMA " : 
-                                       (c0 & 0x80) ? "PIO " : "off ",
-                               (c1 & 0x10) ? "UDMA" : (c1 & 0x20) ? "DMA " :
-                                       (c1 & 0x80) ? "PIO " : "off ",
-                               (c2 & 0x10) ? "UDMA" : (c2 & 0x20) ? "DMA " :
-                                       (c2 & 0x80) ? "PIO " : "off ",
-                               (c3 & 0x10) ? "UDMA" : (c3 & 0x20) ? "DMA " :
-                                       (c3 & 0x80) ? "PIO " : "off ");
-               }
-       }
-#endif
+/*
+ *     Hold all the highpoint quirks and revision information in one
+ *     place.
+ */
 
-static u32 hpt_revision (struct pci_dev *dev)
+struct hpt_info
+{
+       u8 max_mode;            /* Speeds allowed */
+       int revision;           /* Chipset revision */
+       int flags;              /* Chipset properties */
+#define PLL_MODE       1
+#define IS_372N                2
+                               /* Speed table */
+       struct chipset_bus_clock_list_entry *speed;
+};
+
+/*
+ *     This wants fixing so that we do everything not by classrev
+ *     (which breaks on the newest chips) but by creating an
+ *     enumeration of chip variants and using that
+ */
+
+static __devinit u32 hpt_revision (struct pci_dev *dev)
 {
        u32 class_rev;
        pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
@@ -507,37 +497,33 @@ static u32 hpt_revision (struct pci_dev *dev)
        return class_rev;
 }
 
-static u32 hpt_minimum_revision (struct pci_dev *dev, int revision)
-{
-       unsigned int class_rev = hpt_revision(dev);
-       revision--;
-       return ((int) (class_rev > revision) ? 1 : 0);
-}
-
 static int check_in_drive_lists(ide_drive_t *drive, const char **list);
 
 static u8 hpt3xx_ratemask (ide_drive_t *drive)
 {
-       struct pci_dev *dev     = HWIF(drive)->pci_dev;
+       ide_hwif_t *hwif        = drive->hwif;
+       struct hpt_info *info   = ide_get_hwifdata(hwif);
        u8 mode                 = 0;
 
-       if (hpt_minimum_revision(dev, 8)) {             /* HPT374 */
+       /* FIXME: TODO - move this to set info->mode once at boot */
+
+       if (info->revision >= 8) {              /* HPT374 */
                mode = (HPT374_ALLOW_ATA133_6) ? 4 : 3;
-       } else if (hpt_minimum_revision(dev, 7)) {      /* HPT371 */
+       } else if (info->revision >= 7) {       /* HPT371 */
                mode = (HPT371_ALLOW_ATA133_6) ? 4 : 3;
-       } else if (hpt_minimum_revision(dev, 6)) {      /* HPT302 */
+       } else if (info->revision >= 6) {       /* HPT302 */
                mode = (HPT302_ALLOW_ATA133_6) ? 4 : 3;
-       } else if (hpt_minimum_revision(dev, 5)) {      /* HPT372 */
+       } else if (info->revision >= 5) {       /* HPT372 */
                mode = (HPT372_ALLOW_ATA133_6) ? 4 : 3;
-       } else if (hpt_minimum_revision(dev, 4)) {      /* HPT370A */
+       } else if (info->revision >= 4) {       /* HPT370A */
                mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
-       } else if (hpt_minimum_revision(dev, 3)) {      /* HPT370 */
+       } else if (info->revision >= 3) {       /* HPT370 */
                mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
                mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : mode;
        } else {                                /* HPT366 and HPT368 */
                mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : 2;
        }
-       if (!eighty_ninty_three(drive) && (mode))
+       if (!eighty_ninty_three(drive) && mode)
                mode = min(mode, (u8)1);
        return mode;
 }
@@ -549,7 +535,8 @@ static u8 hpt3xx_ratemask (ide_drive_t *drive)
  
 static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
 {
-       struct pci_dev *dev     = HWIF(drive)->pci_dev;
+       ide_hwif_t *hwif        = drive->hwif;
+       struct hpt_info *info   = ide_get_hwifdata(hwif);
        u8 mode                 = hpt3xx_ratemask(drive);
 
        if (drive->media != ide_disk)
@@ -561,7 +548,7 @@ static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
                        break;
                case 0x03:
                        speed = min(speed, (u8)XFER_UDMA_5);
-                       if (hpt_minimum_revision(dev, 5))
+                       if (info->revision >= 5)
                                break;
                        if (check_in_drive_lists(drive, bad_ata100_5))
                                speed = min(speed, (u8)XFER_UDMA_4);
@@ -571,7 +558,7 @@ static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
        /*
         * CHECK ME, Does this need to be set to 5 ??
         */
-                       if (hpt_minimum_revision(dev, 3))
+                       if (info->revision >= 3)
                                break;
                        if ((check_in_drive_lists(drive, bad_ata66_4)) ||
                            (!(HPT366_ALLOW_ATA66_4)))
@@ -585,7 +572,7 @@ static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
        /*
         * CHECK ME, Does this need to be set to 5 ??
         */
-                       if (hpt_minimum_revision(dev, 3))
+                       if (info->revision >= 3)
                                break;
                        if (check_in_drive_lists(drive, bad_ata33))
                                speed = min(speed, (u8)XFER_MW_DMA_2);
@@ -624,11 +611,12 @@ static unsigned int pci_bus_clock_list (u8 speed, struct chipset_bus_clock_list_
 
 static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
 {
-       struct pci_dev *dev     = HWIF(drive)->pci_dev;
+       ide_hwif_t *hwif        = drive->hwif;
+       struct pci_dev *dev     = hwif->pci_dev;
+       struct hpt_info *info   = ide_get_hwifdata(hwif);
        u8 speed                = hpt3xx_ratefilter(drive, xferspeed);
-//     u8 speed                = ide_rate_filter(hpt3xx_ratemask(drive), xferspeed);
        u8 regtime              = (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
-       u8 regfast              = (HWIF(drive)->channel) ? 0x55 : 0x51;
+       u8 regfast              = (hwif->channel) ? 0x55 : 0x51;
        u8 drive_fast           = 0;
        u32 reg1 = 0, reg2      = 0;
 
@@ -636,16 +624,11 @@ static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
         * Disable the "fast interrupt" prediction.
         */
        pci_read_config_byte(dev, regfast, &drive_fast);
-#if 0
-       if (drive_fast & 0x02)
-               pci_write_config_byte(dev, regfast, drive_fast & ~0x20);
-#else
        if (drive_fast & 0x80)
                pci_write_config_byte(dev, regfast, drive_fast & ~0x80);
-#endif
 
-       reg2 = pci_bus_clock_list(speed,
-               (struct chipset_bus_clock_list_entry *) pci_get_drvdata(dev));
+       reg2 = pci_bus_clock_list(speed, info->speed);
+
        /*
         * Disable on-chip PIO FIFO/buffer
         *  (to avoid problems handling I/O errors later)
@@ -665,10 +648,11 @@ static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
 
 static int hpt370_tune_chipset(ide_drive_t *drive, u8 xferspeed)
 {
-       struct pci_dev *dev = HWIF(drive)->pci_dev;
+       ide_hwif_t *hwif        = drive->hwif;
+       struct pci_dev *dev = hwif->pci_dev;
+       struct hpt_info *info   = ide_get_hwifdata(hwif);
        u8 speed        = hpt3xx_ratefilter(drive, xferspeed);
-//     u8 speed        = ide_rate_filter(hpt3xx_ratemask(drive), xferspeed);
-       u8 regfast      = (HWIF(drive)->channel) ? 0x55 : 0x51;
+       u8 regfast      = (drive->hwif->channel) ? 0x55 : 0x51;
        u8 drive_pci    = 0x40 + (drive->dn * 4);
        u8 new_fast     = 0, drive_fast = 0;
        u32 list_conf   = 0, drive_conf = 0;
@@ -693,17 +677,13 @@ static int hpt370_tune_chipset(ide_drive_t *drive, u8 xferspeed)
        if (new_fast != drive_fast)
                pci_write_config_byte(dev, regfast, new_fast);
 
-       list_conf = pci_bus_clock_list(speed, 
-                                      (struct chipset_bus_clock_list_entry *)
-                                      pci_get_drvdata(dev));
+       list_conf = pci_bus_clock_list(speed, info->speed);
 
        pci_read_config_dword(dev, drive_pci, &drive_conf);
        list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
        
-       if (speed < XFER_MW_DMA_0) {
+       if (speed < XFER_MW_DMA_0)
                list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
-       }
-
        pci_write_config_dword(dev, drive_pci, list_conf);
 
        return ide_config_drive_speed(drive, speed);
@@ -711,10 +691,11 @@ static int hpt370_tune_chipset(ide_drive_t *drive, u8 xferspeed)
 
 static int hpt372_tune_chipset(ide_drive_t *drive, u8 xferspeed)
 {
-       struct pci_dev *dev     = HWIF(drive)->pci_dev;
+       ide_hwif_t *hwif        = drive->hwif;
+       struct pci_dev *dev     = hwif->pci_dev;
+       struct hpt_info *info   = ide_get_hwifdata(hwif);
        u8 speed        = hpt3xx_ratefilter(drive, xferspeed);
-//     u8 speed        = ide_rate_filter(hpt3xx_ratemask(drive), xferspeed);
-       u8 regfast      = (HWIF(drive)->channel) ? 0x55 : 0x51;
+       u8 regfast      = (drive->hwif->channel) ? 0x55 : 0x51;
        u8 drive_fast   = 0, drive_pci = 0x40 + (drive->dn * 4);
        u32 list_conf   = 0, drive_conf = 0;
        u32 conf_mask   = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
@@ -726,10 +707,8 @@ static int hpt372_tune_chipset(ide_drive_t *drive, u8 xferspeed)
        pci_read_config_byte(dev, regfast, &drive_fast);
        drive_fast &= ~0x07;
        pci_write_config_byte(dev, regfast, drive_fast);
-                                       
-       list_conf = pci_bus_clock_list(speed,
-                       (struct chipset_bus_clock_list_entry *)
-                                       pci_get_drvdata(dev));
+
+       list_conf = pci_bus_clock_list(speed, info->speed);
        pci_read_config_dword(dev, drive_pci, &drive_conf);
        list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
        if (speed < XFER_MW_DMA_0)
@@ -741,19 +720,14 @@ static int hpt372_tune_chipset(ide_drive_t *drive, u8 xferspeed)
 
 static int hpt3xx_tune_chipset (ide_drive_t *drive, u8 speed)
 {
-       struct pci_dev *dev     = HWIF(drive)->pci_dev;
+       ide_hwif_t *hwif        = drive->hwif;
+       struct hpt_info *info   = ide_get_hwifdata(hwif);
 
-       if (hpt_minimum_revision(dev, 8))
+       if (info->revision >= 8)
                return hpt372_tune_chipset(drive, speed); /* not a typo */
-#if 0
-       else if (hpt_minimum_revision(dev, 7))
-               hpt371_tune_chipset(drive, speed);
-       else if (hpt_minimum_revision(dev, 6))
-               hpt302_tune_chipset(drive, speed);
-#endif
-       else if (hpt_minimum_revision(dev, 5))
+       else if (info->revision >= 5)
                return hpt372_tune_chipset(drive, speed);
-       else if (hpt_minimum_revision(dev, 3))
+       else if (info->revision >= 3)
                return hpt370_tune_chipset(drive, speed);
        else    /* hpt368: hpt_minimum_revision(dev, 2) */
                return hpt36x_tune_chipset(drive, speed);
@@ -779,8 +753,14 @@ static void hpt3xx_tune_drive (ide_drive_t *drive, u8 pio)
 static int config_chipset_for_dma (ide_drive_t *drive)
 {
        u8 speed = ide_dma_speed(drive, hpt3xx_ratemask(drive));
+       ide_hwif_t *hwif = drive->hwif;
+       struct hpt_info *info   = ide_get_hwifdata(hwif);
 
-       if (!(speed))
+       if (!speed)
+               return 0;
+
+       /* If we don't have any timings we can't do a lot */
+       if (info->speed == NULL)
                return 0;
 
        (void) hpt3xx_tune_chipset(drive, speed);
@@ -794,7 +774,7 @@ static int hpt3xx_quirkproc (ide_drive_t *drive)
 
 static void hpt3xx_intrproc (ide_drive_t *drive)
 {
-       ide_hwif_t *hwif = HWIF(drive);
+       ide_hwif_t *hwif = drive->hwif;
 
        if (drive->quirk_list)
                return;
@@ -804,24 +784,26 @@ static void hpt3xx_intrproc (ide_drive_t *drive)
 
 static void hpt3xx_maskproc (ide_drive_t *drive, int mask)
 {
-       struct pci_dev *dev = HWIF(drive)->pci_dev;
+       ide_hwif_t *hwif = drive->hwif;
+       struct hpt_info *info = ide_get_hwifdata(hwif);
+       struct pci_dev *dev = hwif->pci_dev;
 
        if (drive->quirk_list) {
-               if (hpt_minimum_revision(dev,3)) {
+               if (info->revision >= 3) {
                        u8 reg5a = 0;
                        pci_read_config_byte(dev, 0x5a, &reg5a);
                        if (((reg5a & 0x10) >> 4) != mask)
                                pci_write_config_byte(dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
                } else {
                        if (mask) {
-                               disable_irq(HWIF(drive)->irq);
+                               disable_irq(hwif->irq);
                        } else {
-                               enable_irq(HWIF(drive)->irq);
+                               enable_irq(hwif->irq);
                        }
                }
        } else {
                if (IDE_CONTROL_REG)
-                       HWIF(drive)->OUTB(mask ? (drive->ctl | 2) :
+                       hwif->OUTB(mask ? (drive->ctl | 2) :
                                                 (drive->ctl & ~2),
                                                 IDE_CONTROL_REG);
        }
@@ -829,12 +811,12 @@ static void hpt3xx_maskproc (ide_drive_t *drive, int mask)
 
 static int hpt366_config_drive_xfer_rate (ide_drive_t *drive)
 {
-       ide_hwif_t *hwif        = HWIF(drive);
+       ide_hwif_t *hwif        = drive->hwif;
        struct hd_driveid *id   = drive->id;
 
        drive->init_speed = 0;
 
-       if (id && (id->capability & 1) && drive->autodma) {
+       if ((id->capability & 1) && drive->autodma) {
 
                if (ide_use_dma(drive)) {
                        if (config_chipset_for_dma(drive))
@@ -868,15 +850,6 @@ static int hpt366_ide_dma_lostirq (ide_drive_t *drive)
                drive->name, __FUNCTION__, reg50h, reg52h, reg5ah);
        if (reg5ah & 0x10)
                pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
-#if 0
-       /* how about we flush and reset, mmmkay? */
-       pci_write_config_byte(dev, 0x51, 0x1F);
-       /* fall through to a reset */
-       case dma_start:
-       case ide_dma_end:
-       /* reset the chips state over and over.. */
-       pci_write_config_byte(dev, 0x51, 0x13);
-#endif
        return __ide_dma_lostirq(drive);
 }
 
@@ -919,7 +892,7 @@ static void hpt370_lostirq_timeout (ide_drive_t *drive)
        u8 dma_stat = 0, dma_cmd = 0;
 
        pci_read_config_byte(HWIF(drive)->pci_dev, reginfo, &bfifo);
-       printk("%s: %d bytes in FIFO\n", drive->name, bfifo);
+       printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo);
        hpt370_clear_engine(drive);
        /* get dma command mode */
        dma_cmd = hwif->INB(hwif->dma_command);
@@ -1047,15 +1020,6 @@ static void hpt372n_rw_disk(ide_drive_t *drive, struct request *rq)
 
 static void hpt3xx_reset (ide_drive_t *drive)
 {
-#if 0
-       unsigned long high_16   = pci_resource_start(HWIF(drive)->pci_dev, 4);
-       u8 reset        = (HWIF(drive)->channel) ? 0x80 : 0x40;
-       u8 reg59h       = 0;
-
-       pci_read_config_byte(HWIF(drive)->pci_dev, 0x59, &reg59h);
-       pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h|reset);
-       pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h);
-#endif
 }
 
 static int hpt3xx_tristate (ide_drive_t * drive, int state)
@@ -1065,8 +1029,6 @@ static int hpt3xx_tristate (ide_drive_t * drive, int state)
        u8 reg59h = 0, reset    = (hwif->channel) ? 0x80 : 0x40;
        u8 regXXh = 0, state_reg= (hwif->channel) ? 0x57 : 0x53;
 
-//     hwif->bus_state = state;
-
        pci_read_config_byte(dev, 0x59, &reg59h);
        pci_read_config_byte(dev, state_reg, &regXXh);
 
@@ -1093,7 +1055,7 @@ static int hpt3xx_tristate (ide_drive_t * drive, int state)
 #define TRISTATE_BIT  0x8000
 static int hpt370_busproc(ide_drive_t * drive, int state)
 {
-       ide_hwif_t *hwif        = HWIF(drive);
+       ide_hwif_t *hwif        = drive->hwif;
        struct pci_dev *dev     = hwif->pci_dev;
        u8 tristate = 0, resetmask = 0, bus_reg = 0;
        u16 tri_reg;
@@ -1148,33 +1110,44 @@ static int hpt370_busproc(ide_drive_t * drive, int state)
        return 0;
 }
 
-static int __devinit init_hpt37x(struct pci_dev *dev)
+static void __devinit hpt366_clocking(ide_hwif_t *hwif)
 {
+       u32 reg1        = 0;
+       struct hpt_info *info = ide_get_hwifdata(hwif);
+
+       pci_read_config_dword(hwif->pci_dev, 0x40, &reg1);
+
+       /* detect bus speed by looking at control reg timing: */
+       switch((reg1 >> 8) & 7) {
+               case 5:
+                       info->speed = forty_base_hpt366;
+                       break;
+               case 9:
+                       info->speed = twenty_five_base_hpt366;
+                       break;
+               case 7:
+               default:
+                       info->speed = thirty_three_base_hpt366;
+                       break;
+       }
+}
+
+static void __devinit hpt37x_clocking(ide_hwif_t *hwif)
+{
+       struct hpt_info *info = ide_get_hwifdata(hwif);
+       struct pci_dev *dev = hwif->pci_dev;
        int adjust, i;
        u16 freq;
        u32 pll;
        u8 reg5bh;
-       u8 reg5ah = 0;
-       unsigned long dmabase = pci_resource_start(dev, 4);
-       u8 did, rid;    
-       int is_372n = 0;
        
-       pci_read_config_byte(dev, 0x5a, &reg5ah);
-       /* interrupt force enable */
-       pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10));
-
-       if(dmabase)
-       {
-               did = inb(dmabase + 0x22);
-               rid = inb(dmabase + 0x28);
-       
-               if((did == 4 && rid == 6) || (did == 5 && rid > 1))
-                       is_372n = 1;
-       }
-
        /*
         * default to pci clock. make sure MA15/16 are set to output
-        * to prevent drives having problems with 40-pin cables.
+        * to prevent drives having problems with 40-pin cables. Needed
+        * for some drives such as IBM-DTLA which will not enter ready
+        * state on reset when PDIAG is a input.
+        *
+        * ToDo: should we set 0x21 when using PLL mode ?
         */
        pci_write_config_byte(dev, 0x5b, 0x23);
 
@@ -1197,9 +1170,7 @@ static int __devinit init_hpt37x(struct pci_dev *dev)
         * Currently we always set up the PLL for the 372N
         */
         
-       pci_set_drvdata(dev, NULL);
-       
-       if(is_372n)
+       if(info->flags & IS_372N)
        {
                printk(KERN_INFO "hpt: HPT372N detected, using 372N timing.\n");
                if(freq < 0x55)
@@ -1227,39 +1198,38 @@ static int __devinit init_hpt37x(struct pci_dev *dev)
                        pll = F_LOW_PCI_66;
        
                if (pll == F_LOW_PCI_33) {
-                       if (hpt_minimum_revision(dev,8))
-                               pci_set_drvdata(dev, (void *) thirty_three_base_hpt374);
-                       else if (hpt_minimum_revision(dev,5))
-                               pci_set_drvdata(dev, (void *) thirty_three_base_hpt372);
-                       else if (hpt_minimum_revision(dev,4))
-                               pci_set_drvdata(dev, (void *) thirty_three_base_hpt370a);
+                       if (info->revision >= 8)
+                               info->speed = thirty_three_base_hpt374;
+                       else if (info->revision >= 5)
+                               info->speed = thirty_three_base_hpt372;
+                       else if (info->revision >= 4)
+                               info->speed = thirty_three_base_hpt370a;
                        else
-                               pci_set_drvdata(dev, (void *) thirty_three_base_hpt370);
-                       printk("HPT37X: using 33MHz PCI clock\n");
+                               info->speed = thirty_three_base_hpt370;
+                       printk(KERN_DEBUG "HPT37X: using 33MHz PCI clock\n");
                } else if (pll == F_LOW_PCI_40) {
                        /* Unsupported */
                } else if (pll == F_LOW_PCI_50) {
-                       if (hpt_minimum_revision(dev,8))
-                               pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
-                       else if (hpt_minimum_revision(dev,5))
-                               pci_set_drvdata(dev, (void *) fifty_base_hpt372);
-                       else if (hpt_minimum_revision(dev,4))
-                               pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+                       if (info->revision >= 8)
+                               info->speed = fifty_base_hpt370a;
+                       else if (info->revision >= 5)
+                               info->speed = fifty_base_hpt372;
+                       else if (info->revision >= 4)
+                               info->speed = fifty_base_hpt370a;
                        else
-                               pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
-                       printk("HPT37X: using 50MHz PCI clock\n");
+                               info->speed = fifty_base_hpt370a;
+                       printk(KERN_DEBUG "HPT37X: using 50MHz PCI clock\n");
                } else {
-                       if (hpt_minimum_revision(dev,8))
-                       {
+                       if (info->revision >= 8) {
                                printk(KERN_ERR "HPT37x: 66MHz timings are not supported.\n");
                        }
-                       else if (hpt_minimum_revision(dev,5))
-                               pci_set_drvdata(dev, (void *) sixty_six_base_hpt372);
-                       else if (hpt_minimum_revision(dev,4))
-                               pci_set_drvdata(dev, (void *) sixty_six_base_hpt370a);
+                       else if (info->revision >= 5)
+                               info->speed = sixty_six_base_hpt372;
+                       else if (info->revision >= 4)
+                               info->speed = sixty_six_base_hpt370a;
                        else
-                               pci_set_drvdata(dev, (void *) sixty_six_base_hpt370);
-                       printk("HPT37X: using 66MHz PCI clock\n");
+                               info->speed = sixty_six_base_hpt370;
+                       printk(KERN_DEBUG "HPT37X: using 66MHz PCI clock\n");
                }
        }
        
@@ -1269,11 +1239,19 @@ static int __devinit init_hpt37x(struct pci_dev *dev)
         * result in slow reads when using a 33MHz PCI clock. we also
         * don't like to use the PLL because it will cause glitches
         * on PRST/SRST when the HPT state engine gets reset.
+        *
+        * ToDo: Use 66MHz PLL when ATA133 devices are present on a
+        * 372 device so we can get ATA133 support
         */
-       if (pci_get_drvdata(dev)) 
+       if (info->speed)
                goto init_hpt37X_done;
+
+       info->flags |= PLL_MODE;
        
        /*
+        * FIXME: make this work correctly, esp with 372N as per
+        * reference driver code.
+        *
         * adjust PLL based upon PCI clock, enable it, and wait for
         * stabilization.
         */
@@ -1298,14 +1276,14 @@ static int __devinit init_hpt37x(struct pci_dev *dev)
                                pci_write_config_dword(dev, 0x5c, 
                                                       pll & ~0x100);
                                pci_write_config_byte(dev, 0x5b, 0x21);
-                               if (hpt_minimum_revision(dev,8))
-                                       pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
-                               else if (hpt_minimum_revision(dev,5))
-                                       pci_set_drvdata(dev, (void *) fifty_base_hpt372);
-                               else if (hpt_minimum_revision(dev,4))
-                                       pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+                               if (info->revision >= 8)
+                                       info->speed = fifty_base_hpt370a;
+                               else if (info->revision >= 5)
+                                       info->speed = fifty_base_hpt372;
+                               else if (info->revision >= 4)
+                                       info->speed = fifty_base_hpt370a;
                                else
-                                       pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+                                       info->speed = fifty_base_hpt370a;
                                printk("HPT37X: using 50MHz internal PLL\n");
                                goto init_hpt37X_done;
                        }
@@ -1318,10 +1296,22 @@ pll_recal:
        } 
 
 init_hpt37X_done:
+       if (!info->speed)
+               printk(KERN_ERR "HPT37X%s: unknown bus timing [%d %d].\n",
+                       (info->flags & IS_372N)?"N":"", pll, freq);
        /* reset state engine */
        pci_write_config_byte(dev, 0x50, 0x37); 
        pci_write_config_byte(dev, 0x54, 0x37); 
        udelay(100);
+}
+
+static int __devinit init_hpt37x(struct pci_dev *dev)
+{
+       u8 reg5ah;
+
+       pci_read_config_byte(dev, 0x5a, &reg5ah);
+       /* interrupt force enable */
+       pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10));
        return 0;
 }
 
@@ -1338,59 +1328,27 @@ static int __devinit init_hpt366(struct pci_dev *dev)
                pci_write_config_byte(dev, 0x51, drive_fast & ~0x80);
        pci_read_config_dword(dev, 0x40, &reg1);
                                                                        
-       /* detect bus speed by looking at control reg timing: */
-       switch((reg1 >> 8) & 7) {
-               case 5:
-                       pci_set_drvdata(dev, (void *) forty_base_hpt366);
-                       break;
-               case 9:
-                       pci_set_drvdata(dev, (void *) twenty_five_base_hpt366);
-                       break;
-               case 7:
-               default:
-                       pci_set_drvdata(dev, (void *) thirty_three_base_hpt366);
-                       break;
-       }
-
-       if (!pci_get_drvdata(dev))
-       {
-               printk(KERN_ERR "hpt366: unknown bus timing.\n");
-               pci_set_drvdata(dev, NULL);
-       }
        return 0;
 }
 
 static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const char *name)
 {
        int ret = 0;
-       u8 test = 0;
-
+       /* FIXME: Not portable */
        if (dev->resource[PCI_ROM_RESOURCE].start)
                pci_write_config_byte(dev, PCI_ROM_ADDRESS,
                        dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
 
-       pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &test);
-       if (test != (L1_CACHE_BYTES / 4))
-               pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
-                       (L1_CACHE_BYTES / 4));
-
-       pci_read_config_byte(dev, PCI_LATENCY_TIMER, &test);
-       if (test != 0x78)
-               pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
+       pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
+       pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
+       pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
+       pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
 
-       pci_read_config_byte(dev, PCI_MIN_GNT, &test);
-       if (test != 0x08)
-               pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
-
-       pci_read_config_byte(dev, PCI_MAX_LAT, &test);
-       if (test != 0x08)
-               pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
-
-       if (hpt_minimum_revision(dev, 3)) {
+       if (hpt_revision(dev) >= 3)
                ret = init_hpt37x(dev);
-       } else {
-               ret =init_hpt366(dev);
-       }
+       else
+               ret = init_hpt366(dev);
+
        if (ret)
                return ret;
 
@@ -1400,27 +1358,16 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
 static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
 {
        struct pci_dev *dev             = hwif->pci_dev;
+       struct hpt_info *info           = ide_get_hwifdata(hwif);
        u8 ata66 = 0, regmask           = (hwif->channel) ? 0x01 : 0x02;
-       u8 did, rid;
-       unsigned long dmabase           = hwif->dma_base;
-       int is_372n = 0;
        
-       if(dmabase)
-       {
-               did = inb(dmabase + 0x22);
-               rid = inb(dmabase + 0x28);
-       
-               if((did == 4 && rid == 6) || (did == 5 && rid > 1))
-                       is_372n = 1;
-       }
-               
        hwif->tuneproc                  = &hpt3xx_tune_drive;
        hwif->speedproc                 = &hpt3xx_tune_chipset;
        hwif->quirkproc                 = &hpt3xx_quirkproc;
        hwif->intrproc                  = &hpt3xx_intrproc;
        hwif->maskproc                  = &hpt3xx_maskproc;
        
-       if(is_372n)
+       if(info->flags & IS_372N)
                hwif->rw_disk = &hpt372n_rw_disk;
 
        /*
@@ -1428,7 +1375,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
         * address lines to access an external eeprom.  To read valid
         * cable detect state the pins must be enabled as inputs.
         */
-       if (hpt_minimum_revision(dev, 8) && PCI_FUNC(dev->devfn) & 1) {
+       if (info->revision >= 8 && (PCI_FUNC(dev->devfn) & 1)) {
                /*
                 * HPT374 PCI function 1
                 * - set bit 15 of reg 0x52 to enable TCBLID as input
@@ -1443,7 +1390,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
                pci_read_config_byte(dev, 0x5a, &ata66);
                pci_write_config_word(dev, 0x52, mcr3);
                pci_write_config_word(dev, 0x56, mcr6);
-       } else if (hpt_minimum_revision(dev, 3)) {
+       } else if (info->revision >= 3) {
                /*
                 * HPT370/372 and 374 pcifn 0
                 * - clear bit 0 of 0x5b to enable P/SCBLID as inputs
@@ -1470,7 +1417,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
                hwif->serialized = hwif->mate->serialized = 1;
 #endif
 
-       if (hpt_minimum_revision(dev,3)) {
+       if (info->revision >= 3) {
                u8 reg5ah = 0;
                        pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
                /*
@@ -1480,8 +1427,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
                 */
                hwif->resetproc = &hpt3xx_reset;
                hwif->busproc   = &hpt370_busproc;
-//             hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
-       } else if (hpt_minimum_revision(dev,2)) {
+       } else if (info->revision >= 2) {
                hwif->resetproc = &hpt3xx_reset;
                hwif->busproc   = &hpt3xx_tristate;
        } else {
@@ -1502,18 +1448,18 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
                hwif->udma_four = ((ata66 & regmask) ? 0 : 1);
        hwif->ide_dma_check = &hpt366_config_drive_xfer_rate;
 
-       if (hpt_minimum_revision(dev,8)) {
+       if (info->revision >= 8) {
                hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
                hwif->ide_dma_end = &hpt374_ide_dma_end;
-       } else if (hpt_minimum_revision(dev,5)) {
+       } else if (info->revision >= 5) {
                hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
                hwif->ide_dma_end = &hpt374_ide_dma_end;
-       } else if (hpt_minimum_revision(dev,3)) {
+       } else if (info->revision >= 3) {
                hwif->dma_start = &hpt370_ide_dma_start;
                hwif->ide_dma_end = &hpt370_ide_dma_end;
                hwif->ide_dma_timeout = &hpt370_ide_dma_timeout;
                hwif->ide_dma_lostirq = &hpt370_ide_dma_lostirq;
-       } else if (hpt_minimum_revision(dev,2))
+       } else if (info->revision >= 2)
                hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
        else
                hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
@@ -1526,6 +1472,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
 
 static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
 {
+       struct hpt_info *info   = ide_get_hwifdata(hwif);
        u8 masterdma    = 0, slavedma = 0;
        u8 dma_new      = 0, dma_old = 0;
        u8 primary      = hwif->channel ? 0x4b : 0x43;
@@ -1535,8 +1482,7 @@ static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
        if (!dmabase)
                return;
                
-       if(pci_get_drvdata(hwif->pci_dev) == NULL)
-       {
+       if(info->speed == NULL) {
                printk(KERN_WARNING "hpt: no known IDE timings, disabling DMA.\n");
                return;
        }
@@ -1559,6 +1505,40 @@ static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
        ide_setup_dma(hwif, dmabase, 8);
 }
 
+/*
+ *     We "borrow" this hook in order to set the data structures
+ *     up early enough before dma or init_hwif calls are made.
+ */
+
+static void __devinit init_iops_hpt366(ide_hwif_t *hwif)
+{
+       struct hpt_info *info = kmalloc(sizeof(struct hpt_info), GFP_KERNEL);
+       unsigned long dmabase = pci_resource_start(hwif->pci_dev, 4);
+       u8 did, rid;
+
+       if(info == NULL) {
+               printk(KERN_WARNING "hpt366: out of memory.\n");
+               return;
+       }
+       memset(info, 0, sizeof(struct hpt_info));
+       ide_set_hwifdata(hwif, info);
+
+       if(dmabase) {
+               did = inb(dmabase + 0x22);
+               rid = inb(dmabase + 0x28);
+
+               if((did == 4 && rid == 6) || (did == 5 && rid > 1))
+                       info->flags |= IS_372N;
+       }
+
+       info->revision = hpt_revision(hwif->pci_dev);
+
+       if (info->revision >= 3)
+               hpt37x_clocking(hwif);
+       else
+               hpt366_clocking(hwif);
+}
+
 static int __devinit init_setup_hpt374(struct pci_dev *dev, ide_pci_device_t *d)
 {
        struct pci_dev *findev = NULL;
@@ -1646,6 +1626,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
                .name           = "HPT366",
                .init_setup     = init_setup_hpt366,
                .init_chipset   = init_chipset_hpt366,
+               .init_iops      = init_iops_hpt366,
                .init_hwif      = init_hwif_hpt366,
                .init_dma       = init_dma_hpt366,
                .channels       = 2,
@@ -1656,6 +1637,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
                .name           = "HPT372A",
                .init_setup     = init_setup_hpt37x,
                .init_chipset   = init_chipset_hpt366,
+               .init_iops      = init_iops_hpt366,
                .init_hwif      = init_hwif_hpt366,
                .init_dma       = init_dma_hpt366,
                .channels       = 2,
@@ -1665,6 +1647,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
                .name           = "HPT302",
                .init_setup     = init_setup_hpt37x,
                .init_chipset   = init_chipset_hpt366,
+               .init_iops      = init_iops_hpt366,
                .init_hwif      = init_hwif_hpt366,
                .init_dma       = init_dma_hpt366,
                .channels       = 2,
@@ -1674,6 +1657,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
                .name           = "HPT371",
                .init_setup     = init_setup_hpt37x,
                .init_chipset   = init_chipset_hpt366,
+               .init_iops      = init_iops_hpt366,
                .init_hwif      = init_hwif_hpt366,
                .init_dma       = init_dma_hpt366,
                .channels       = 2,
@@ -1683,6 +1667,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
                .name           = "HPT374",
                .init_setup     = init_setup_hpt374,
                .init_chipset   = init_chipset_hpt366,
+               .init_iops      = init_iops_hpt366,
                .init_hwif      = init_hwif_hpt366,
                .init_dma       = init_dma_hpt366,
                .channels       = 2,    /* 4 */
@@ -1692,6 +1677,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
                .name           = "HPT372N",
                .init_setup     = init_setup_hpt37x,
                .init_chipset   = init_chipset_hpt366,
+               .init_iops      = init_iops_hpt366,
                .init_hwif      = init_hwif_hpt366,
                .init_dma       = init_dma_hpt366,
                .channels       = 2,    /* 4 */
diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c
new file mode 100644 (file)
index 0000000..e440036
--- /dev/null
@@ -0,0 +1,812 @@
+
+/*
+ * linux/drivers/ide/pci/it821x.c              Version 0.09    December 2004
+ *
+ * Copyright (C) 2004          Red Hat <alan@redhat.com>
+ *
+ *  May be copied or modified under the terms of the GNU General Public License
+ *  Based in part on the ITE vendor provided SCSI driver.
+ *
+ *  Documentation available from
+ *     http://www.ite.com.tw/pc/IT8212F_V04.pdf
+ *  Some other documents are NDA.
+ *
+ *  The ITE8212 isn't exactly a standard IDE controller. It has two
+ *  modes. In pass through mode then it is an IDE controller. In its smart
+ *  mode its actually quite a capable hardware raid controller disguised
+ *  as an IDE controller. Smart mode only understands DMA read/write and
+ *  identify, none of the fancier commands apply. The IT8211 is identical
+ *  in other respects but lacks the raid mode.
+ *
+ *  Errata:
+ *  o  Rev 0x10 also requires master/slave hold the same DMA timings and
+ *     cannot do ATAPI MWDMA.
+ *  o  The identify data for raid volumes lacks CHS info (technically ok)
+ *     but also fails to set the LBA28 and other bits. We fix these in
+ *     the IDE probe quirk code.
+ *  o  If you write LBA48 sized I/O's (ie > 256 sector) in smart mode
+ *     raid then the controller firmware dies
+ *  o  Smart mode without RAID doesn't clear all the necessary identify
+ *     bits to reduce the command set to the one used
+ *
+ *  This has a few impacts on the driver
+ *  - In pass through mode we do all the work you would expect
+ *  - In smart mode the clocking set up is done by the controller generally
+ *    but we must watch the other limits and filter.
+ *  - There are a few extra vendor commands that actually talk to the
+ *    controller but only work PIO with no IRQ.
+ *
+ *  Vendor areas of the identify block in smart mode are used for the
+ *  timing and policy set up. Each HDD in raid mode also has a serial
+ *  block on the disk. The hardware extra commands are get/set chip status,
+ *  rebuild, get rebuild status.
+ *
+ *  In Linux the driver supports pass through mode as if the device was
+ *  just another IDE controller. If the smart mode is running then
+ *  volumes are managed by the controller firmware and each IDE "disk"
+ *  is a raid volume. Even more cute - the controller can do automated
+ *  hotplug and rebuild.
+ *
+ *  The pass through controller itself is a little demented. It has a
+ *  flaw that it has a single set of PIO/MWDMA timings per channel so
+ *  non UDMA devices restrict each others performance. It also has a
+ *  single clock source per channel so mixed UDMA100/133 performance
+ *  isn't perfect and we have to pick a clock. Thankfully none of this
+ *  matters in smart mode. ATAPI DMA is not currently supported.
+ *
+ *  It seems the smart mode is a win for RAID1/RAID10 but otherwise not.
+ *
+ *  TODO
+ *     -       ATAPI UDMA is ok but not MWDMA it seems
+ *     -       RAID configuration ioctls
+ *     -       Move to libata once it grows up
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+struct it821x_dev
+{
+       unsigned int smart:1,           /* Are we in smart raid mode */
+               timing10:1;             /* Rev 0x10 */
+       u8      clock_mode;             /* 0, ATA_50 or ATA_66 */
+       u8      want[2][2];             /* Mode/Pri log for master slave */
+       /* We need these for switching the clock when DMA goes on/off
+          The high byte is the 66Mhz timing */
+       u16     pio[2];                 /* Cached PIO values */
+       u16     mwdma[2];               /* Cached MWDMA values */
+       u16     udma[2];                /* Cached UDMA values (per drive) */
+};
+
+#define ATA_66         0
+#define ATA_50         1
+#define ATA_ANY                2
+
+#define UDMA_OFF       0
+#define MWDMA_OFF      0
+
+/*
+ *     We allow users to force the card into non raid mode without
+ *     flashing the alternative BIOS. This is also neccessary right now
+ *     for embedded platforms that cannot run a PC BIOS but are using this
+ *     device.
+ */
+
+static int it8212_noraid;
+
+/**
+ *     it821x_program  -       program the PIO/MWDMA registers
+ *     @drive: drive to tune
+ *
+ *     Program the PIO/MWDMA timing for this channel according to the
+ *     current clock.
+ */
+
+static void it821x_program(ide_drive_t *drive, u16 timing)
+{
+       ide_hwif_t *hwif        = drive->hwif;
+       struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+       int channel = hwif->channel;
+       u8 conf;
+
+       /* Program PIO/MWDMA timing bits */
+       if(itdev->clock_mode == ATA_66)
+               conf = timing >> 8;
+       else
+               conf = timing & 0xFF;
+       pci_write_config_byte(hwif->pci_dev, 0x54 + 4 * channel, conf);
+}
+
+/**
+ *     it821x_program_udma     -       program the UDMA registers
+ *     @drive: drive to tune
+ *
+ *     Program the UDMA timing for this drive according to the
+ *     current clock.
+ */
+
+static void it821x_program_udma(ide_drive_t *drive, u16 timing)
+{
+       ide_hwif_t *hwif        = drive->hwif;
+       struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+       int channel = hwif->channel;
+       int unit = drive->select.b.unit;
+       u8 conf;
+
+       /* Program UDMA timing bits */
+       if(itdev->clock_mode == ATA_66)
+               conf = timing >> 8;
+       else
+               conf = timing & 0xFF;
+       if(itdev->timing10 == 0)
+               pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel + unit, conf);
+       else {
+               pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel, conf);
+               pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel + 1, conf);
+       }
+}
+
+
+/**
+ *     it821x_clock_strategy
+ *     @hwif: hardware interface
+ *
+ *     Select between the 50 and 66Mhz base clocks to get the best
+ *     results for this interface.
+ */
+
+static void it821x_clock_strategy(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+
+       u8 unit = drive->select.b.unit;
+       ide_drive_t *pair = &hwif->drives[1-unit];
+
+       int clock, altclock;
+       u8 v;
+       int sel = 0;
+
+       if(itdev->want[0][0] > itdev->want[1][0]) {
+               clock = itdev->want[0][1];
+               altclock = itdev->want[1][1];
+       } else {
+               clock = itdev->want[1][1];
+               altclock = itdev->want[0][1];
+       }
+
+       /* Master doesn't care does the slave ? */
+       if(clock == ATA_ANY)
+               clock = altclock;
+
+       /* Nobody cares - keep the same clock */
+       if(clock == ATA_ANY)
+               return;
+       /* No change */
+       if(clock == itdev->clock_mode)
+               return;
+
+       /* Load this into the controller ? */
+       if(clock == ATA_66)
+               itdev->clock_mode = ATA_66;
+       else {
+               itdev->clock_mode = ATA_50;
+               sel = 1;
+       }
+       pci_read_config_byte(hwif->pci_dev, 0x50, &v);
+       v &= ~(1 << (1 + hwif->channel));
+       v |= sel << (1 + hwif->channel);
+       pci_write_config_byte(hwif->pci_dev, 0x50, v);
+
+       /*
+        *      Reprogram the UDMA/PIO of the pair drive for the switch
+        *      MWDMA will be dealt with by the dma switcher
+        */
+       if(pair && itdev->udma[1-unit] != UDMA_OFF) {
+               it821x_program_udma(pair, itdev->udma[1-unit]);
+               it821x_program(pair, itdev->pio[1-unit]);
+       }
+       /*
+        *      Reprogram the UDMA/PIO of our drive for the switch.
+        *      MWDMA will be dealt with by the dma switcher
+        */
+       if(itdev->udma[unit] != UDMA_OFF) {
+               it821x_program_udma(drive, itdev->udma[unit]);
+               it821x_program(drive, itdev->pio[unit]);
+       }
+}
+
+/**
+ *     it821x_ratemask -       Compute available modes
+ *     @drive: IDE drive
+ *
+ *     Compute the available speeds for the devices on the interface. This
+ *     is all modes to ATA133 clipped by drive cable setup.
+ */
+
+static u8 it821x_ratemask (ide_drive_t *drive)
+{
+       u8 mode = 4;
+       if (!eighty_ninty_three(drive))
+               mode = min(mode, (u8)1);
+       return mode;
+}
+
+/**
+ *     it821x_tuneproc -       tune a drive
+ *     @drive: drive to tune
+ *     @mode_wanted: the target operating mode
+ *
+ *     Load the timing settings for this device mode into the
+ *     controller. By the time we are called the mode has been
+ *     modified as neccessary to handle the absence of seperate
+ *     master/slave timers for MWDMA/PIO.
+ *
+ *     This code is only used in pass through mode.
+ */
+
+static void it821x_tuneproc (ide_drive_t *drive, byte mode_wanted)
+{
+       ide_hwif_t *hwif        = drive->hwif;
+       struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+       int unit = drive->select.b.unit;
+
+       /* Spec says 89 ref driver uses 88 */
+       static u16 pio[]        = { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 };
+       static u8 pio_want[]    = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY };
+
+       if(itdev->smart)
+               return;
+
+       /* We prefer 66Mhz clock for PIO 0-3, don't care for PIO4 */
+       itdev->want[unit][1] = pio_want[mode_wanted];
+       itdev->want[unit][0] = 1;       /* PIO is lowest priority */
+       itdev->pio[unit] = pio[mode_wanted];
+       it821x_clock_strategy(drive);
+       it821x_program(drive, itdev->pio[unit]);
+}
+
+/**
+ *     it821x_tune_mwdma       -       tune a channel for MWDMA
+ *     @drive: drive to set up
+ *     @mode_wanted: the target operating mode
+ *
+ *     Load the timing settings for this device mode into the
+ *     controller when doing MWDMA in pass through mode. The caller
+ *     must manage the whole lack of per device MWDMA/PIO timings and
+ *     the shared MWDMA/PIO timing register.
+ */
+
+static void it821x_tune_mwdma (ide_drive_t *drive, byte mode_wanted)
+{
+       ide_hwif_t *hwif        = drive->hwif;
+       struct it821x_dev *itdev = (void *)ide_get_hwifdata(hwif);
+       int unit = drive->select.b.unit;
+       int channel = hwif->channel;
+       u8 conf;
+
+       static u16 dma[]        = { 0x8866, 0x3222, 0x3121 };
+       static u8 mwdma_want[]  = { ATA_ANY, ATA_66, ATA_ANY };
+
+       itdev->want[unit][1] = mwdma_want[mode_wanted];
+       itdev->want[unit][0] = 2;       /* MWDMA is low priority */
+       itdev->mwdma[unit] = dma[mode_wanted];
+       itdev->udma[unit] = UDMA_OFF;
+
+       /* UDMA bits off - Revision 0x10 do them in pairs */
+       pci_read_config_byte(hwif->pci_dev, 0x50, &conf);
+       if(itdev->timing10)
+               conf |= channel ? 0x60: 0x18;
+       else
+               conf |= 1 << (3 + 2 * channel + unit);
+       pci_write_config_byte(hwif->pci_dev, 0x50, conf);
+
+       it821x_clock_strategy(drive);
+       /* FIXME: do we need to program this ? */
+       /* it821x_program(drive, itdev->mwdma[unit]); */
+}
+
+/**
+ *     it821x_tune_udma        -       tune a channel for UDMA
+ *     @drive: drive to set up
+ *     @mode_wanted: the target operating mode
+ *
+ *     Load the timing settings for this device mode into the
+ *     controller when doing UDMA modes in pass through.
+ */
+
+static void it821x_tune_udma (ide_drive_t *drive, byte mode_wanted)
+{
+       ide_hwif_t *hwif        = drive->hwif;
+       struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+       int unit = drive->select.b.unit;
+       int channel = hwif->channel;
+       u8 conf;
+
+       static u16 udma[]       = { 0x4433, 0x4231, 0x3121, 0x2121, 0x1111, 0x2211, 0x1111 };
+       static u8 udma_want[]   = { ATA_ANY, ATA_50, ATA_ANY, ATA_66, ATA_66, ATA_50, ATA_66 };
+
+       itdev->want[unit][1] = udma_want[mode_wanted];
+       itdev->want[unit][0] = 3;       /* UDMA is high priority */
+       itdev->mwdma[unit] = MWDMA_OFF;
+       itdev->udma[unit] = udma[mode_wanted];
+       if(mode_wanted >= 5)
+               itdev->udma[unit] |= 0x8080;    /* UDMA 5/6 select on */
+
+       /* UDMA on. Again revision 0x10 must do the pair */
+       pci_read_config_byte(hwif->pci_dev, 0x50, &conf);
+       if(itdev->timing10)
+               conf &= channel ? 0x9F: 0xE7;
+       else
+               conf &= ~ (1 << (3 + 2 * channel + unit));
+       pci_write_config_byte(hwif->pci_dev, 0x50, conf);
+
+       it821x_clock_strategy(drive);
+       it821x_program_udma(drive, itdev->udma[unit]);
+
+}
+
+/**
+ *     config_it821x_chipset_for_pio   -       set drive timings
+ *     @drive: drive to tune
+ *     @speed we want
+ *
+ *     Compute the best pio mode we can for a given device. We must
+ *     pick a speed that does not cause problems with the other device
+ *     on the cable.
+ */
+
+static void config_it821x_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+       u8 unit = drive->select.b.unit;
+       ide_hwif_t *hwif = drive->hwif;
+       ide_drive_t *pair = &hwif->drives[1-unit];
+       u8 speed = 0, set_pio   = ide_get_best_pio_mode(drive, 255, 5, NULL);
+       u8 pair_pio;
+
+       /* We have to deal with this mess in pairs */
+       if(pair != NULL) {
+               pair_pio = ide_get_best_pio_mode(pair, 255, 5, NULL);
+               /* Trim PIO to the slowest of the master/slave */
+               if(pair_pio < set_pio)
+                       set_pio = pair_pio;
+       }
+       it821x_tuneproc(drive, set_pio);
+       speed = XFER_PIO_0 + set_pio;
+       /* XXX - We trim to the lowest of the pair so the other drive
+          will always be fine at this point until we do hotplug passthru */
+
+       if (set_speed)
+               (void) ide_config_drive_speed(drive, speed);
+}
+
+/**
+ *     it821x_dma_read -       DMA hook
+ *     @drive: drive for DMA
+ *
+ *     The IT821x has a single timing register for MWDMA and for PIO
+ *     operations. As we flip back and forth we have to reload the
+ *     clock. In addition the rev 0x10 device only works if the same
+ *     timing value is loaded into the master and slave UDMA clock
+ *     so we must also reload that.
+ *
+ *     FIXME: we could figure out in advance if we need to do reloads
+ */
+
+static void it821x_dma_start(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+       int unit = drive->select.b.unit;
+       if(itdev->mwdma[unit] != MWDMA_OFF)
+               it821x_program(drive, itdev->mwdma[unit]);
+       else if(itdev->udma[unit] != UDMA_OFF && itdev->timing10)
+               it821x_program_udma(drive, itdev->udma[unit]);
+       ide_dma_start(drive);
+}
+
+/**
+ *     it821x_dma_write        -       DMA hook
+ *     @drive: drive for DMA stop
+ *
+ *     The IT821x has a single timing register for MWDMA and for PIO
+ *     operations. As we flip back and forth we have to reload the
+ *     clock.
+ */
+
+static int it821x_dma_end(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       int unit = drive->select.b.unit;
+       struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+       int ret = __ide_dma_end(drive);
+       if(itdev->mwdma[unit] != MWDMA_OFF)
+               it821x_program(drive, itdev->pio[unit]);
+       return ret;
+}
+
+
+/**
+ *     it821x_tune_chipset     -       set controller timings
+ *     @drive: Drive to set up
+ *     @xferspeed: speed we want to achieve
+ *
+ *     Tune the ITE chipset for the desired mode. If we can't achieve
+ *     the desired mode then tune for a lower one, but ultimately
+ *     make the thing work.
+ */
+
+static int it821x_tune_chipset (ide_drive_t *drive, byte xferspeed)
+{
+
+       ide_hwif_t *hwif        = drive->hwif;
+       struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+       u8 speed                = ide_rate_filter(it821x_ratemask(drive), xferspeed);
+
+       if(!itdev->smart) {
+               switch(speed) {
+                       case XFER_PIO_4:
+                       case XFER_PIO_3:
+                       case XFER_PIO_2:
+                       case XFER_PIO_1:
+                       case XFER_PIO_0:
+                               it821x_tuneproc(drive, (speed - XFER_PIO_0));
+                               break;
+                       /* MWDMA tuning is really hard because our MWDMA and PIO
+                          timings are kept in the same place. We can switch in the
+                          host dma on/off callbacks */
+                       case XFER_MW_DMA_2:
+                       case XFER_MW_DMA_1:
+                       case XFER_MW_DMA_0:
+                               it821x_tune_mwdma(drive, (speed - XFER_MW_DMA_0));
+                               break;
+                       case XFER_UDMA_6:
+                       case XFER_UDMA_5:
+                       case XFER_UDMA_4:
+                       case XFER_UDMA_3:
+                       case XFER_UDMA_2:
+                       case XFER_UDMA_1:
+                       case XFER_UDMA_0:
+                               it821x_tune_udma(drive, (speed - XFER_UDMA_0));
+                               break;
+                       default:
+                               return 1;
+               }
+       }
+       /*
+        *      In smart mode the clocking is done by the host controller
+        *      snooping the mode we picked. The rest of it is not our problem
+        */
+       return ide_config_drive_speed(drive, speed);
+}
+
+/**
+ *     config_chipset_for_dma  -       configure for DMA
+ *     @drive: drive to configure
+ *
+ *     Called by the IDE layer when it wants the timings set up.
+ */
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+       u8 speed        = ide_dma_speed(drive, it821x_ratemask(drive));
+
+       config_it821x_chipset_for_pio(drive, !speed);
+       it821x_tune_chipset(drive, speed);
+       return ide_dma_enable(drive);
+}
+
+/**
+ *     it821x_configure_drive_for_dma  -       set up for DMA transfers
+ *     @drive: drive we are going to set up
+ *
+ *     Set up the drive for DMA, tune the controller and drive as
+ *     required. If the drive isn't suitable for DMA or we hit
+ *     other problems then we will drop down to PIO and set up
+ *     PIO appropriately
+ */
+
+static int it821x_config_drive_for_dma (ide_drive_t *drive)
+{
+       ide_hwif_t *hwif        = drive->hwif;
+
+       if (ide_use_dma(drive)) {
+               if (config_chipset_for_dma(drive))
+                       return hwif->ide_dma_on(drive);
+       }
+       config_it821x_chipset_for_pio(drive, 1);
+       return hwif->ide_dma_off_quietly(drive);
+}
+
+/**
+ *     ata66_it821x    -       check for 80 pin cable
+ *     @hwif: interface to check
+ *
+ *     Check for the presence of an ATA66 capable cable on the
+ *     interface. Problematic as it seems some cards don't have
+ *     the needed logic onboard.
+ */
+
+static unsigned int __devinit ata66_it821x(ide_hwif_t *hwif)
+{
+       /* The reference driver also only does disk side */
+       return 1;
+}
+
+/**
+ *     it821x_fixup    -       post init callback
+ *     @hwif: interface
+ *
+ *     This callback is run after the drives have been probed but
+ *     before anything gets attached. It allows drivers to do any
+ *     final tuning that is needed, or fixups to work around bugs.
+ */
+
+static void __devinit it821x_fixups(ide_hwif_t *hwif)
+{
+       struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+       int i;
+
+       if(!itdev->smart) {
+               /*
+                *      If we are in pass through mode then not much
+                *      needs to be done, but we do bother to clear the
+                *      IRQ mask as we may well be in PIO (eg rev 0x10)
+                *      for now and we know unmasking is safe on this chipset.
+                */
+               for (i = 0; i < 2; i++) {
+                       ide_drive_t *drive = &hwif->drives[i];
+                       if(drive->present)
+                               drive->unmask = 1;
+               }
+               return;
+       }
+       /*
+        *      Perform fixups on smart mode. We need to "lose" some
+        *      capabilities the firmware lacks but does not filter, and
+        *      also patch up some capability bits that it forgets to set
+        *      in RAID mode.
+        */
+
+       for(i = 0; i < 2; i++) {
+               ide_drive_t *drive = &hwif->drives[i];
+               struct hd_driveid *id;
+               u16 *idbits;
+
+               if(!drive->present)
+                       continue;
+               id = drive->id;
+               idbits = (u16 *)drive->id;
+
+               /* Check for RAID v native */
+               if(strstr(id->model, "Integrated Technology Express")) {
+                       /* In raid mode the ident block is slightly buggy
+                          We need to set the bits so that the IDE layer knows
+                          LBA28. LBA48 and DMA ar valid */
+                       id->capability |= 3;            /* LBA28, DMA */
+                       id->command_set_2 |= 0x0400;    /* LBA48 valid */
+                       id->cfs_enable_2 |= 0x0400;     /* LBA48 on */
+                       /* Reporting logic */
+                       printk(KERN_INFO "%s: IT8212 %sRAID %d volume",
+                               drive->name,
+                               idbits[147] ? "Bootable ":"",
+                               idbits[129]);
+                               if(idbits[129] != 1)
+                                       printk("(%dK stripe)", idbits[146]);
+                               printk(".\n");
+                       /* Now the core code will have wrongly decided no DMA
+                          so we need to fix this */
+                       hwif->ide_dma_off_quietly(drive);
+#ifdef CONFIG_IDEDMA_ONLYDISK
+                       if (drive->media == ide_disk)
+#endif
+                               hwif->ide_dma_check(drive);
+               } else {
+                       /* Non RAID volume. Fixups to stop the core code
+                          doing unsupported things */
+                       id->field_valid &= 1;
+                       id->queue_depth = 0;
+                       id->command_set_1 = 0;
+                       id->command_set_2 &= 0xC400;
+                       id->cfsse &= 0xC000;
+                       id->cfs_enable_1 = 0;
+                       id->cfs_enable_2 &= 0xC400;
+                       id->csf_default &= 0xC000;
+                       id->word127 = 0;
+                       id->dlf = 0;
+                       id->csfo = 0;
+                       id->cfa_power = 0;
+                       printk(KERN_INFO "%s: Performing identify fixups.\n",
+                               drive->name);
+               }
+       }
+
+}
+
+/**
+ *     init_hwif_it821x        -       set up hwif structs
+ *     @hwif: interface to set up
+ *
+ *     We do the basic set up of the interface structure. The IT8212
+ *     requires several custom handlers so we override the default
+ *     ide DMA handlers appropriately
+ */
+
+static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
+{
+       struct it821x_dev *idev = kmalloc(sizeof(struct it821x_dev), GFP_KERNEL);
+       u8 conf;
+
+       if(idev == NULL) {
+               printk(KERN_ERR "it821x: out of memory, falling back to legacy behaviour.\n");
+               goto fallback;
+       }
+       memset(idev, 0, sizeof(struct it821x_dev));
+       ide_set_hwifdata(hwif, idev);
+
+       pci_read_config_byte(hwif->pci_dev, 0x50, &conf);
+       if(conf & 1) {
+               idev->smart = 1;
+               hwif->atapi_dma = 0;
+               /* Long I/O's although allowed in LBA48 space cause the
+                  onboard firmware to enter the twighlight zone */
+               hwif->rqsize = 256;
+       }
+
+       /* Pull the current clocks from 0x50 also */
+       if (conf & (1 << (1 + hwif->channel)))
+               idev->clock_mode = ATA_50;
+       else
+               idev->clock_mode = ATA_66;
+
+       idev->want[0][1] = ATA_ANY;
+       idev->want[1][1] = ATA_ANY;
+
+       /*
+        *      Not in the docs but according to the reference driver
+        *      this is neccessary.
+        */
+
+       pci_read_config_byte(hwif->pci_dev, 0x08, &conf);
+       if(conf == 0x10) {
+               idev->timing10 = 1;
+               hwif->atapi_dma = 0;
+               if(!idev->smart)
+                       printk(KERN_WARNING "it821x: Revision 0x10, workarounds activated.\n");
+       }
+
+       hwif->speedproc = &it821x_tune_chipset;
+       hwif->tuneproc  = &it821x_tuneproc;
+
+       /* MWDMA/PIO clock switching for pass through mode */
+       if(!idev->smart) {
+               hwif->dma_start = &it821x_dma_start;
+               hwif->ide_dma_end = &it821x_dma_end;
+       }
+
+       hwif->drives[0].autotune = 1;
+       hwif->drives[1].autotune = 1;
+
+       if (!hwif->dma_base)
+               goto fallback;
+
+       hwif->ultra_mask = 0x7f;
+       hwif->mwdma_mask = 0x07;
+       hwif->swdma_mask = 0x07;
+
+       hwif->ide_dma_check = &it821x_config_drive_for_dma;
+       if (!(hwif->udma_four))
+               hwif->udma_four = ata66_it821x(hwif);
+
+       /*
+        *      The BIOS often doesn't set up DMA on this controller
+        *      so we always do it.
+        */
+
+       hwif->autodma = 1;
+       hwif->drives[0].autodma = hwif->autodma;
+       hwif->drives[1].autodma = hwif->autodma;
+       return;
+fallback:
+       hwif->autodma = 0;
+       return;
+}
+
+static void __devinit it8212_disable_raid(struct pci_dev *dev)
+{
+       /* Reset local CPU, and set BIOS not ready */
+       pci_write_config_byte(dev, 0x5E, 0x01);
+
+       /* Set to bypass mode, and reset PCI bus */
+       pci_write_config_byte(dev, 0x50, 0x00);
+       pci_write_config_word(dev, PCI_COMMAND,
+                             PCI_COMMAND_PARITY | PCI_COMMAND_IO |
+                             PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+       pci_write_config_word(dev, 0x40, 0xA0F3);
+
+       pci_write_config_dword(dev,0x4C, 0x02040204);
+       pci_write_config_byte(dev, 0x42, 0x36);
+       pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0);
+}
+
+static unsigned int __devinit init_chipset_it821x(struct pci_dev *dev, const char *name)
+{
+       u8 conf;
+       static char *mode[2] = { "pass through", "smart" };
+
+       /* Force the card into bypass mode if so requested */
+       if (it8212_noraid) {
+               printk(KERN_INFO "it8212: forcing bypass mode.\n");
+               it8212_disable_raid(dev);
+       }
+       pci_read_config_byte(dev, 0x50, &conf);
+       printk(KERN_INFO "it821x: controller in %s mode.\n", mode[conf & 1]);
+       return 0;
+}
+
+
+#define DECLARE_ITE_DEV(name_str)                      \
+       {                                               \
+               .name           = name_str,             \
+               .init_chipset   = init_chipset_it821x,  \
+               .init_hwif      = init_hwif_it821x,     \
+               .channels       = 2,                    \
+               .autodma        = AUTODMA,              \
+               .bootable       = ON_BOARD,             \
+               .fixup          = it821x_fixups         \
+       }
+
+static ide_pci_device_t it821x_chipsets[] __devinitdata = {
+       /* 0 */ DECLARE_ITE_DEV("IT8212"),
+};
+
+/**
+ *     it821x_init_one -       pci layer discovery entry
+ *     @dev: PCI device
+ *     @id: ident table entry
+ *
+ *     Called by the PCI code when it finds an ITE821x controller.
+ *     We then use the IDE PCI generic helper to do most of the work.
+ */
+
+static int __devinit it821x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+       ide_setup_pci_device(dev, &it821x_chipsets[id->driver_data]);
+       return 0;
+}
+
+static struct pci_device_id it821x_pci_tbl[] = {
+       { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8211,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8212,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       { 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, it821x_pci_tbl);
+
+static struct pci_driver driver = {
+       .name           = "ITE821x IDE",
+       .id_table       = it821x_pci_tbl,
+       .probe          = it821x_init_one,
+};
+
+static int __init it821x_ide_init(void)
+{
+       return ide_pci_register_driver(&driver);
+}
+
+module_init(it821x_ide_init);
+
+module_param_named(noraid, it8212_noraid, int, S_IRUGO);
+MODULE_PARM_DESC(it8212_noraid, "Force card into bypass mode");
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("PCI driver module for the ITE 821x");
+MODULE_LICENSE("GPL");
index 82a1103..c6f5fa4 100644 (file)
@@ -442,7 +442,7 @@ static unsigned int __devinit init_chipset_svwks (struct pci_dev *dev, const cha
        return (dev->irq) ? dev->irq : 0;
 }
 
-static unsigned int __init ata66_svwks_svwks (ide_hwif_t *hwif)
+static unsigned int __devinit ata66_svwks_svwks (ide_hwif_t *hwif)
 {
        return 1;
 }
@@ -454,7 +454,7 @@ static unsigned int __init ata66_svwks_svwks (ide_hwif_t *hwif)
  * Bit 14 clear = primary IDE channel does not have 80-pin cable.
  * Bit 14 set   = primary IDE channel has 80-pin cable.
  */
-static unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif)
+static unsigned int __devinit ata66_svwks_dell (ide_hwif_t *hwif)
 {
        struct pci_dev *dev = hwif->pci_dev;
        if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
@@ -472,7 +472,7 @@ static unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif)
  *
  * WARNING: this only works on Alpine hardware!
  */
-static unsigned int __init ata66_svwks_cobalt (ide_hwif_t *hwif)
+static unsigned int __devinit ata66_svwks_cobalt (ide_hwif_t *hwif)
 {
        struct pci_dev *dev = hwif->pci_dev;
        if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN &&
@@ -483,7 +483,7 @@ static unsigned int __init ata66_svwks_cobalt (ide_hwif_t *hwif)
        return 0;
 }
 
-static unsigned int __init ata66_svwks (ide_hwif_t *hwif)
+static unsigned int __devinit ata66_svwks (ide_hwif_t *hwif)
 {
        struct pci_dev *dev = hwif->pci_dev;
 
@@ -573,7 +573,7 @@ static int __devinit init_setup_svwks (struct pci_dev *dev, ide_pci_device_t *d)
        return ide_setup_pci_device(dev, d);
 }
 
-static int __init init_setup_csb6 (struct pci_dev *dev, ide_pci_device_t *d)
+static int __devinit init_setup_csb6 (struct pci_dev *dev, ide_pci_device_t *d)
 {
        if (!(PCI_FUNC(dev->devfn) & 1)) {
                d->bootable = NEVER_BOARD;
index c77a82e..3e72c9b 100644 (file)
 #include <linux/init.h>
 #include <linux/gameport.h>
 #include <linux/wait.h>
-#include <linux/completion.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/kthread.h>
 
 /*#include <asm/io.h>*/
 
@@ -238,8 +237,7 @@ struct gameport_event {
 static DEFINE_SPINLOCK(gameport_event_lock);   /* protects gameport_event_list */
 static LIST_HEAD(gameport_event_list);
 static DECLARE_WAIT_QUEUE_HEAD(gameport_wait);
-static DECLARE_COMPLETION(gameport_exited);
-static int gameport_pid;
+static struct task_struct *gameport_task;
 
 static void gameport_queue_event(void *object, struct module *owner,
                              enum gameport_event_type event_type)
@@ -250,12 +248,12 @@ static void gameport_queue_event(void *object, struct module *owner,
        spin_lock_irqsave(&gameport_event_lock, flags);
 
        /*
-        * Scan event list for the other events for the same gameport port,
+        * Scan event list for the other events for the same gameport port,
         * starting with the most recent one. If event is the same we
         * do not need add new one. If event is of different type we
         * need to add this event and should not look further because
         * we need to preseve sequence of distinct events.
-        */
+        */
        list_for_each_entry_reverse(event, &gameport_event_list, node) {
                if (event->object == object) {
                        if (event->type == event_type)
@@ -432,20 +430,15 @@ static struct gameport *gameport_get_pending_child(struct gameport *parent)
 
 static int gameport_thread(void *nothing)
 {
-       lock_kernel();
-       daemonize("kgameportd");
-       allow_signal(SIGTERM);
-
        do {
                gameport_handle_events();
-               wait_event_interruptible(gameport_wait, !list_empty(&gameport_event_list));
+               wait_event_interruptible(gameport_wait,
+                       kthread_should_stop() || !list_empty(&gameport_event_list));
                try_to_freeze();
-       } while (!signal_pending(current));
+       } while (!kthread_should_stop());
 
        printk(KERN_DEBUG "gameport: kgameportd exiting\n");
-
-       unlock_kernel();
-       complete_and_exit(&gameport_exited, 0);
+       return 0;
 }
 
 
@@ -773,9 +766,10 @@ void gameport_close(struct gameport *gameport)
 
 static int __init gameport_init(void)
 {
-       if (!(gameport_pid = kernel_thread(gameport_thread, NULL, CLONE_KERNEL))) {
+       gameport_task = kthread_run(gameport_thread, NULL, "kgameportd");
+       if (IS_ERR(gameport_task)) {
                printk(KERN_ERR "gameport: Failed to start kgameportd\n");
-               return -1;
+               return PTR_ERR(gameport_task);
        }
 
        gameport_bus.dev_attrs = gameport_device_attrs;
@@ -789,8 +783,7 @@ static int __init gameport_init(void)
 static void __exit gameport_exit(void)
 {
        bus_unregister(&gameport_bus);
-       kill_proc(gameport_pid, SIGTERM, 1);
-       wait_for_completion(&gameport_exited);
+       kthread_stop(gameport_task);
 }
 
 module_init(gameport_init);
index 341824c..f367695 100644 (file)
 #include <linux/serio.h>
 #include <linux/errno.h>
 #include <linux/wait.h>
-#include <linux/completion.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
+#include <linux/kthread.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("Serio abstraction core");
@@ -43,6 +42,7 @@ MODULE_LICENSE("GPL");
 EXPORT_SYMBOL(serio_interrupt);
 EXPORT_SYMBOL(__serio_register_port);
 EXPORT_SYMBOL(serio_unregister_port);
+EXPORT_SYMBOL(serio_unregister_child_port);
 EXPORT_SYMBOL(__serio_unregister_port_delayed);
 EXPORT_SYMBOL(__serio_register_driver);
 EXPORT_SYMBOL(serio_unregister_driver);
@@ -68,6 +68,37 @@ static void serio_destroy_port(struct serio *serio);
 static void serio_reconnect_port(struct serio *serio);
 static void serio_disconnect_port(struct serio *serio);
 
+static int serio_connect_driver(struct serio *serio, struct serio_driver *drv)
+{
+       int retval;
+
+       down(&serio->drv_sem);
+       retval = drv->connect(serio, drv);
+       up(&serio->drv_sem);
+
+       return retval;
+}
+
+static int serio_reconnect_driver(struct serio *serio)
+{
+       int retval = -1;
+
+       down(&serio->drv_sem);
+       if (serio->drv && serio->drv->reconnect)
+               retval = serio->drv->reconnect(serio);
+       up(&serio->drv_sem);
+
+       return retval;
+}
+
+static void serio_disconnect_driver(struct serio *serio)
+{
+       down(&serio->drv_sem);
+       if (serio->drv)
+               serio->drv->disconnect(serio);
+       up(&serio->drv_sem);
+}
+
 static int serio_match_port(const struct serio_device_id *ids, struct serio *serio)
 {
        while (ids->type || ids->proto) {
@@ -91,7 +122,7 @@ static void serio_bind_driver(struct serio *serio, struct serio_driver *drv)
 
        if (serio_match_port(drv->id_table, serio)) {
                serio->dev.driver = &drv->driver;
-               if (drv->connect(serio, drv)) {
+               if (serio_connect_driver(serio, drv)) {
                        serio->dev.driver = NULL;
                        goto out;
                }
@@ -138,8 +169,7 @@ struct serio_event {
 static DEFINE_SPINLOCK(serio_event_lock);      /* protects serio_event_list */
 static LIST_HEAD(serio_event_list);
 static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
-static DECLARE_COMPLETION(serio_exited);
-static int serio_pid;
+static struct task_struct *serio_task;
 
 static void serio_queue_event(void *object, struct module *owner,
                              enum serio_event_type event_type)
@@ -150,12 +180,12 @@ static void serio_queue_event(void *object, struct module *owner,
        spin_lock_irqsave(&serio_event_lock, flags);
 
        /*
-        * Scan event list for the other events for the same serio port,
+        * Scan event list for the other events for the same serio port,
         * starting with the most recent one. If event is the same we
         * do not need add new one. If event is of different type we
         * need to add this event and should not look further because
         * we need to preseve sequence of distinct events.
-        */
+        */
        list_for_each_entry_reverse(event, &serio_event_list, node) {
                if (event->object == object) {
                        if (event->type == event_type)
@@ -337,20 +367,15 @@ static struct serio *serio_get_pending_child(struct serio *parent)
 
 static int serio_thread(void *nothing)
 {
-       lock_kernel();
-       daemonize("kseriod");
-       allow_signal(SIGTERM);
-
        do {
                serio_handle_events();
-               wait_event_interruptible(serio_wait, !list_empty(&serio_event_list));
+               wait_event_interruptible(serio_wait,
+                       kthread_should_stop() || !list_empty(&serio_event_list));
                try_to_freeze();
-       } while (!signal_pending(current));
+       } while (!kthread_should_stop());
 
        printk(KERN_DEBUG "serio: kseriod exiting\n");
-
-       unlock_kernel();
-       complete_and_exit(&serio_exited, 0);
+       return 0;
 }
 
 
@@ -557,7 +582,7 @@ static void serio_destroy_port(struct serio *serio)
 static void serio_reconnect_port(struct serio *serio)
 {
        do {
-               if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) {
+               if (serio_reconnect_driver(serio)) {
                        serio_disconnect_port(serio);
                        serio_find_driver(serio);
                        /* Ok, old children are now gone, we are done */
@@ -629,6 +654,19 @@ void serio_unregister_port(struct serio *serio)
        up(&serio_sem);
 }
 
+/*
+ * Safely unregisters child port if one is present.
+ */
+void serio_unregister_child_port(struct serio *serio)
+{
+       down(&serio_sem);
+       if (serio->child) {
+               serio_disconnect_port(serio->child);
+               serio_destroy_port(serio->child);
+       }
+       up(&serio_sem);
+}
+
 /*
  * Submits register request to kseriod for subsequent execution.
  * Can be used when it is not obvious whether the serio_sem is
@@ -686,15 +724,14 @@ static int serio_driver_probe(struct device *dev)
        struct serio *serio = to_serio_port(dev);
        struct serio_driver *drv = to_serio_driver(dev->driver);
 
-       return drv->connect(serio, drv);
+       return serio_connect_driver(serio, drv);
 }
 
 static int serio_driver_remove(struct device *dev)
 {
        struct serio *serio = to_serio_port(dev);
-       struct serio_driver *drv = to_serio_driver(dev->driver);
 
-       drv->disconnect(serio);
+       serio_disconnect_driver(serio);
        return 0;
 }
 
@@ -730,11 +767,9 @@ start_over:
 
 static void serio_set_drv(struct serio *serio, struct serio_driver *drv)
 {
-       down(&serio->drv_sem);
        serio_pause_rx(serio);
        serio->drv = drv;
        serio_continue_rx(serio);
-       up(&serio->drv_sem);
 }
 
 static int serio_bus_match(struct device *dev, struct device_driver *drv)
@@ -794,7 +829,7 @@ static int serio_resume(struct device *dev)
 {
        struct serio *serio = to_serio_port(dev);
 
-       if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) {
+       if (serio_reconnect_driver(serio)) {
                /*
                 * Driver re-probing can take a while, so better let kseriod
                 * deal with it.
@@ -848,9 +883,10 @@ irqreturn_t serio_interrupt(struct serio *serio,
 
 static int __init serio_init(void)
 {
-       if (!(serio_pid = kernel_thread(serio_thread, NULL, CLONE_KERNEL))) {
+       serio_task = kthread_run(serio_thread, NULL, "kseriod");
+       if (IS_ERR(serio_task)) {
                printk(KERN_ERR "serio: Failed to start kseriod\n");
-               return -1;
+               return PTR_ERR(serio_task);
        }
 
        serio_bus.dev_attrs = serio_device_attrs;
@@ -866,8 +902,7 @@ static int __init serio_init(void)
 static void __exit serio_exit(void)
 {
        bus_unregister(&serio_bus);
-       kill_proc(serio_pid, SIGTERM, 1);
-       wait_for_completion(&serio_exited);
+       kthread_stop(serio_task);
 }
 
 module_init(serio_init);
index dc00c85..ee750e9 100644 (file)
@@ -486,6 +486,14 @@ static int avmcs_event(event_t event, int priority,
     return 0;
 } /* avmcs_event */
 
+static struct pcmcia_device_id avmcs_ids[] = {
+       PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN-Controller B1", 0x95d42008, 0x845dc335),
+       PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M1", 0x95d42008, 0x81e10430),
+       PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M2", 0x95d42008, 0x18e8558a),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, avmcs_ids);
+
 static struct pcmcia_driver avmcs_driver = {
        .owner  = THIS_MODULE,
        .drv    = {
@@ -493,6 +501,7 @@ static struct pcmcia_driver avmcs_driver = {
        },
        .attach = avmcs_attach,
        .detach = avmcs_detach,
+       .id_table = avmcs_ids,
 };
 
 static int __init avmcs_init(void)
index 663a0bf..67c60e0 100644 (file)
@@ -501,6 +501,13 @@ static int avma1cs_event(event_t event, int priority,
     return 0;
 } /* avma1cs_event */
 
+static struct pcmcia_device_id avma1cs_ids[] = {
+       PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb),
+       PCMCIA_DEVICE_PROD_ID12("ISDN", "CARD", 0x8d9761c8, 0x01c5aa7b),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, avma1cs_ids);
+
 static struct pcmcia_driver avma1cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -508,6 +515,7 @@ static struct pcmcia_driver avma1cs_driver = {
        },
        .attach         = avma1cs_attach,
        .detach         = avma1cs_detach,
+       .id_table       = avma1cs_ids,
 };
  
 /*====================================================================*/
index bfc0132..9146be5 100644 (file)
@@ -508,6 +508,13 @@ static int elsa_cs_event(event_t event, int priority,
     return 0;
 } /* elsa_cs_event */
 
+static struct pcmcia_device_id elsa_ids[] = {
+       PCMCIA_DEVICE_PROD_ID12("ELSA AG (Aachen, Germany)", "MicroLink ISDN/MC ", 0x983de2c4, 0x333ba257),
+       PCMCIA_DEVICE_PROD_ID12("ELSA GmbH, Aachen", "MicroLink ISDN/MC ", 0x639e5718, 0x333ba257),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, elsa_ids);
+
 static struct pcmcia_driver elsa_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -515,6 +522,7 @@ static struct pcmcia_driver elsa_cs_driver = {
        },
        .attach         = elsa_cs_attach,
        .detach         = elsa_cs_detach,
+       .id_table       = elsa_ids,
 };
 
 static int __init init_elsa_cs(void)
index 4496512..058147a 100644 (file)
@@ -616,6 +616,18 @@ static int sedlbauer_event(event_t event, int priority,
     return 0;
 } /* sedlbauer_event */
 
+static struct pcmcia_device_id sedlbauer_ids[] = {
+       PCMCIA_DEVICE_PROD_ID1234("SEDLBAUER", "speed star II", "V 3.1", "(c) 93 - 98 cb ", 0x81fb79f5, 0xf3612e1d, 0x6b95c78a, 0x50d4149c),
+       PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D67", 0x81fb79f5, 0xe4e9bc12, 0x397b7e90),
+       PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D98", 0x81fb79f5, 0xe4e9bc12, 0x2e5c7fce),
+       PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", " (C) 93-94 VK", 0x81fb79f5, 0xe4e9bc12, 0x8db143fe),
+       PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", " (c) 93-95 VK", 0x81fb79f5, 0xe4e9bc12, 0xb391ab4c),
+       PCMCIA_DEVICE_PROD_ID12("HST High Soft Tech GmbH", "Saphir II B", 0xd79e0b84, 0x21d083ae),
+/*     PCMCIA_DEVICE_PROD_ID1234("SEDLBAUER", 0x81fb79f5), */ /* too generic*/
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, sedlbauer_ids);
+
 static struct pcmcia_driver sedlbauer_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -623,6 +635,7 @@ static struct pcmcia_driver sedlbauer_driver = {
        },
        .attach         = sedlbauer_attach,
        .detach         = sedlbauer_detach,
+       .id_table       = sedlbauer_ids,
 };
 
 static int __init init_sedlbauer_cs(void)
index 63e8e20..107376f 100644 (file)
@@ -489,6 +489,12 @@ static int teles_cs_event(event_t event, int priority,
     return 0;
 } /* teles_cs_event */
 
+static struct pcmcia_device_id teles_ids[] = {
+       PCMCIA_DEVICE_PROD_ID12("TELES", "S0/PC", 0x67b50eae, 0xe9e70119),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, teles_ids);
+
 static struct pcmcia_driver teles_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -496,6 +502,7 @@ static struct pcmcia_driver teles_cs_driver = {
        },
        .attach         = teles_attach,
        .detach         = teles_detach,
+       .id_table       = teles_ids,
 };
 
 static int __init init_teles_cs(void)
index 8480057..2bea2e0 100644 (file)
@@ -607,6 +607,16 @@ config MTD_PCMCIA
          cards are usually around 4-16MiB in size. This does not include
          Compact Flash cards which are treated as IDE devices.
 
+config MTD_PCMCIA_ANONYMOUS
+       bool "Use PCMCIA MTD drivers for anonymous PCMCIA cards"
+       depends on MTD_PCMCIA
+       default N
+       help
+         If this option is enabled, PCMCIA cards which do not report
+         anything about themselves are assumed to be MTD cards.
+
+         If unsure, say N.
+
 config MTD_UCLINUX
        tristate "Generic uClinux RAM/ROM filesystem support"
        depends on MTD_PARTITIONS && !MMU
index e37b4c1..c2655a8 100644 (file)
@@ -818,6 +818,32 @@ static dev_link_t *pcmciamtd_attach(void)
        return link;
 }
 
+static struct pcmcia_device_id pcmciamtd_ids[] = {
+       PCMCIA_DEVICE_FUNC_ID(1),
+       PCMCIA_DEVICE_PROD_ID123("IO DATA", "PCS-2M", "2MB SRAM", 0x547e66dc, 0x1fed36cd, 0x36eadd21),
+       PCMCIA_DEVICE_PROD_ID12("IBM", "2MB SRAM", 0xb569a6e5, 0x36eadd21),
+       PCMCIA_DEVICE_PROD_ID12("IBM", "4MB FLASH", 0xb569a6e5, 0x8bc54d2a),
+       PCMCIA_DEVICE_PROD_ID12("IBM", "8MB FLASH", 0xb569a6e5, 0x6df1be3e),
+       PCMCIA_DEVICE_PROD_ID12("Intel", "S2E20SW", 0x816cc815, 0xd14c9dcf),
+       PCMCIA_DEVICE_PROD_ID12("Intel", "S2E8 SW", 0x816cc815, 0xa2d7dedb),
+       PCMCIA_DEVICE_PROD_ID12("intel", "SERIES2-02 ", 0x40ade711, 0x145cea5c),
+       PCMCIA_DEVICE_PROD_ID12("intel", "SERIES2-04 ", 0x40ade711, 0x42064dda),
+       PCMCIA_DEVICE_PROD_ID12("intel", "SERIES2-20 ", 0x40ade711, 0x25ee5cb0),
+       PCMCIA_DEVICE_PROD_ID12("intel", "VALUE SERIES 100 ", 0x40ade711, 0xdf8506d8),
+       PCMCIA_DEVICE_PROD_ID12("KINGMAX TECHNOLOGY INC.", "SRAM 256K Bytes", 0x54d0c69c, 0xad12c29c),
+       PCMCIA_DEVICE_PROD_ID12("Maxtor", "MAXFL MobileMax Flash Memory Card", 0xb68968c8, 0x2dfb47b0),
+       PCMCIA_DEVICE_PROD_ID12("SEIKO EPSON", "WWB101EN20", 0xf9876baf, 0xad0b207b),
+       PCMCIA_DEVICE_PROD_ID12("SEIKO EPSON", "WWB513EN20", 0xf9876baf, 0xe8d884ad),
+       PCMCIA_DEVICE_PROD_ID12("Starfish, Inc.", "REX-3000", 0x05ddca47, 0xe7d67bca),
+       PCMCIA_DEVICE_PROD_ID12("Starfish, Inc.", "REX-4100", 0x05ddca47, 0x7bc32944),
+       /* the following was commented out in pcmcia-cs-3.2.7 */
+       /* PCMCIA_DEVICE_PROD_ID12("RATOC Systems,Inc.", "SmartMedia ADAPTER PC Card", 0xf4a2fefe, 0x5885b2ae), */
+#ifdef CONFIG_MTD_PCMCIA_ANONYMOUS
+       { .match_flags = PCMCIA_DEV_ID_MATCH_ANONYMOUS, },
+#endif
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, pcmciamtd_ids);
 
 static struct pcmcia_driver pcmciamtd_driver = {
        .drv            = {
@@ -825,7 +851,8 @@ static struct pcmcia_driver pcmciamtd_driver = {
        },
        .attach         = pcmciamtd_attach,
        .detach         = pcmciamtd_detach,
-       .owner          = THIS_MODULE
+       .owner          = THIS_MODULE,
+       .id_table       = pcmciamtd_ids,
 };
 
 
index c6e8b25..f0fc04b 100644 (file)
@@ -1286,6 +1286,13 @@ static int el3_close(struct net_device *dev)
        return 0;
 }
 
+static struct pcmcia_device_id tc574_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0574),
+       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0556, "3CCFEM556.cis"),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, tc574_ids);
+
 static struct pcmcia_driver tc574_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -1293,6 +1300,7 @@ static struct pcmcia_driver tc574_driver = {
        },
        .attach         = tc574_attach,
        .detach         = tc574_detach,
+       .id_table       = tc574_ids,
 };
 
 static int __init init_tc574(void)
index 89abdda..8fa1b5f 100644 (file)
@@ -1057,6 +1057,17 @@ static int el3_close(struct net_device *dev)
     return 0;
 }
 
+static struct pcmcia_device_id tc589_ids[] = {
+       PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0101, 0x0562),
+       PCMCIA_MFC_DEVICE_PROD_ID1(0, "Motorola MARQUIS", 0xf03e4e77),
+       PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0589),
+       PCMCIA_DEVICE_PROD_ID12("Farallon", "ENet", 0x58d93fc4, 0x992c2202),
+       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0035, "3CXEM556.cis"),
+       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x003d, "3CXEM556.cis"),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, tc589_ids);
+
 static struct pcmcia_driver tc589_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -1064,6 +1075,7 @@ static struct pcmcia_driver tc589_driver = {
        },
        .attach         = tc589_attach,
        .detach         = tc589_detach,
+        .id_table       = tc589_ids,
 };
 
 static int __init init_tc589(void)
index 853b586..23ce77b 100644 (file)
@@ -850,6 +850,34 @@ static void block_output(struct net_device *dev, int count,
     outsw(nic_base + AXNET_DATAPORT, buf, count>>1);
 }
 
+static struct pcmcia_device_id axnet_ids[] = {
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x016c, 0x0081),
+       PCMCIA_DEVICE_MANF_CARD(0x018a, 0x0301),
+       PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0301),
+       PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0303),
+       PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0309),
+       PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1106),
+       PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab),
+       PCMCIA_DEVICE_PROD_ID124("Fast Ethernet", "16-bit PC Card", "AX88190", 0xb4be14e3, 0x9a12eb6a, 0xab9be5ef),
+       PCMCIA_DEVICE_PROD_ID12("ASIX", "AX88190", 0x0959823b, 0xab9be5ef),
+       PCMCIA_DEVICE_PROD_ID12("Billionton", "LNA-100B", 0x552ab682, 0xbc3b87e1),
+       PCMCIA_DEVICE_PROD_ID12("CHEETAH ETHERCARD", "EN2228", 0x00fa7bc8, 0x00e990cc),
+       PCMCIA_DEVICE_PROD_ID12("CNet", "CNF301", 0xbc477dde, 0x78c5f40b),
+       PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEther PCC-TXD", 0x5261440f, 0x436768c5),
+       PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEtherII PCC-TXD", 0x5261440f, 0x730df72e),
+       PCMCIA_DEVICE_PROD_ID12("Dynalink", "L100C16", 0x55632fd5, 0x66bc2a90),
+       PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 PC Card (PCMPC100 V3)", 0x0733cc81, 0x232019a8),
+       PCMCIA_DEVICE_PROD_ID12("MELCO", "LPC3-TX", 0x481e0094, 0xf91af609),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "100BASE", 0x281f1c5d, 0x7c2add04),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FastEtherCard", 0x281f1c5d, 0x7ef26116),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FEP501", 0x281f1c5d, 0x2e272058),
+       PCMCIA_DEVICE_PROD_ID14("Network Everywhere", "AX88190", 0x820a67b6,  0xab9be5ef),
+       /* this is not specific enough */
+       /* PCMCIA_DEVICE_MANF_CARD(0x021b, 0x0202), */
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, axnet_ids);
+
 static struct pcmcia_driver axnet_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -857,6 +885,7 @@ static struct pcmcia_driver axnet_cs_driver = {
        },
        .attach         = axnet_attach,
        .detach         = axnet_detach,
+       .id_table       = axnet_ids,
 };
 
 static int __init init_axnet_cs(void)
index 4294e1e..68d58cc 100644 (file)
@@ -483,7 +483,11 @@ static int com20020_event(event_t event, int priority,
     return 0;
 } /* com20020_event */
 
-
+static struct pcmcia_device_id com20020_ids[] = {
+       PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.", "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, com20020_ids);
 
 static struct pcmcia_driver com20020_cs_driver = {
        .owner          = THIS_MODULE,
@@ -492,6 +496,7 @@ static struct pcmcia_driver com20020_cs_driver = {
        },
        .attach         = com20020_attach,
        .detach         = com20020_detach,
+       .id_table       = com20020_ids,
 };
 
 static int __init init_com20020_cs(void)
index 0424865..917adbb 100644 (file)
@@ -435,7 +435,9 @@ static void fmvj18x_config(dev_link_t *link)
                pcmcia_get_status(handle, &status);
                if (status.CardState & CS_EVENT_3VCARD)
                    link->conf.Vcc = 33; /* inserted in 3.3V slot */
-           } else if (le16_to_cpu(buf[1]) == PRODID_TDK_GN3410) {
+           } else if (le16_to_cpu(buf[1]) == PRODID_TDK_GN3410
+                       || le16_to_cpu(buf[1]) == PRODID_TDK_NP9610
+                       || le16_to_cpu(buf[1]) == PRODID_TDK_MN3200) {
                /* MultiFunction Card */
                link->conf.ConfigBase = 0x800;
                link->conf.ConfigIndex = 0x47;
@@ -764,6 +766,31 @@ static int fmvj18x_event(event_t event, int priority,
     return 0;
 } /* fmvj18x_event */
 
+static struct pcmcia_device_id fmvj18x_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(0x0004, 0x0004),
+       PCMCIA_DEVICE_PROD_ID12("EAGLE Technology", "NE200 ETHERNET LAN MBH10302 04", 0x528c88c4, 0x74f91e59),
+       PCMCIA_DEVICE_PROD_ID12("Eiger Labs,Inc", "EPX-10BT PC Card Ethernet 10BT", 0x53af556e, 0x877f9922),
+       PCMCIA_DEVICE_PROD_ID12("Eiger labs,Inc.", "EPX-10BT PC Card Ethernet 10BT", 0xf47e6c66, 0x877f9922),
+       PCMCIA_DEVICE_PROD_ID12("FUJITSU", "LAN Card(FMV-J182)", 0x6ee5a3d8, 0x5baf31db),
+       PCMCIA_DEVICE_PROD_ID12("FUJITSU", "MBH10308", 0x6ee5a3d8, 0x3f04875e),
+       PCMCIA_DEVICE_PROD_ID12("FUJITSU TOWA", "LA501", 0xb8451188, 0x12939ba2),
+       PCMCIA_DEVICE_PROD_ID12("HITACHI", "HT-4840-11", 0xf4f43949, 0x773910f4),
+       PCMCIA_DEVICE_PROD_ID12("NextComK.K.", "NC5310B Ver1.0       ", 0x8cef4d3a, 0x075fc7b6),
+       PCMCIA_DEVICE_PROD_ID12("NextComK.K.", "NC5310 Ver1.0        ", 0x8cef4d3a, 0xbccf43e6),
+       PCMCIA_DEVICE_PROD_ID12("RATOC System Inc.", "10BASE_T CARD R280", 0x85c10e17, 0xd9413666),
+       PCMCIA_DEVICE_PROD_ID12("TDK", "LAC-CD02x", 0x1eae9475, 0x8fa0ee70),
+       PCMCIA_DEVICE_PROD_ID12("TDK", "LAC-CF010", 0x1eae9475, 0x7683bc9a),
+       PCMCIA_DEVICE_PROD_ID1("CONTEC Co.,Ltd.", 0x58d8fee2),
+       PCMCIA_DEVICE_PROD_ID1("PCMCIA LAN MBH10304  ES", 0x2599f454),
+       PCMCIA_DEVICE_PROD_ID1("PCMCIA MBH10302", 0x8f4005da),
+       PCMCIA_DEVICE_PROD_ID1("UBKK,V2.0", 0x90888080),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "TDK", "GlobalNetworker 3410/3412", 0x1eae9475, 0xd9a93bed),
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0x0d0a),
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0x0e0a),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, fmvj18x_ids);
+
 static struct pcmcia_driver fmvj18x_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -771,6 +798,7 @@ static struct pcmcia_driver fmvj18x_cs_driver = {
        },
        .attach         = fmvj18x_attach,
        .detach         = fmvj18x_detach,
+       .id_table       = fmvj18x_ids,
 };
 
 static int __init init_fmvj18x_cs(void)
index f0ff06e..cf6d073 100644 (file)
@@ -508,6 +508,13 @@ static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase)
     return;
 }
 
+static struct pcmcia_device_id ibmtr_ids[] = {
+       PCMCIA_DEVICE_PROD_ID12("3Com", "TokenLink Velocity PC Card", 0x41240e5b, 0x82c3734e),
+       PCMCIA_DEVICE_PROD_ID12("IBM", "TOKEN RING", 0xb569a6e5, 0xbf8eed47),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, ibmtr_ids);
+
 static struct pcmcia_driver ibmtr_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -515,6 +522,7 @@ static struct pcmcia_driver ibmtr_cs_driver = {
        },
        .attach         = ibmtr_attach,
        .detach         = ibmtr_detach,
+       .id_table       = ibmtr_ids,
 };
 
 static int __init init_ibmtr_cs(void)
index 4603807..b86e725 100644 (file)
@@ -1675,6 +1675,13 @@ static void set_multicast_list(struct net_device *dev)
 
 } /* set_multicast_list */
 
+static struct pcmcia_device_id nmclan_ids[] = {
+       PCMCIA_DEVICE_PROD_ID12("New Media Corporation", "Ethernet", 0x085a850b, 0x00b2e941),
+       PCMCIA_DEVICE_PROD_ID12("Portable Add-ons", "Ethernet", 0x0ebf1d60, 0x00b2e941),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, nmclan_ids);
+
 static struct pcmcia_driver nmclan_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -1682,6 +1689,7 @@ static struct pcmcia_driver nmclan_cs_driver = {
        },
        .attach         = nmclan_attach,
        .detach         = nmclan_detach,
+       .id_table       = nmclan_ids,
 };
 
 static int __init init_nmclan_cs(void)
index f3ea4a9..855a45d 100644 (file)
@@ -1637,6 +1637,208 @@ failed:
 
 /*====================================================================*/
 
+static struct pcmcia_device_id pcnet_ids[] = {
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0057, 0x0021),
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0104, 0x000a),
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0xea15),
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0143, 0x3341),
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0143, 0xc0ab),
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x021b, 0x0101),
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x08a1, 0xc0ab),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "AnyCom", "Fast Ethernet ", 0x578ba6e7, 0x02d92d1e),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "D-Link", "DME336T", 0x1a424a1c, 0xb23897ff),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "Grey Cell", "GCS3000", 0x2a151fac, 0x48b932ae),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "Linksys", "EtherFast 10&100 + 56K PC Card (PCMLM56)", 0x0733cc81, 0xb3765033),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "PCMCIAs", "LanModem", 0xdcfe12d3, 0xc67c648f),
+       PCMCIA_MFC_DEVICE_PROD_ID12(0, "IBM", "Home and Away 28.8 PC Card       ", 0xb569a6e5, 0x5bd4ff2c),
+       PCMCIA_MFC_DEVICE_PROD_ID12(0, "IBM", "Home and Away Credit Card Adapter", 0xb569a6e5, 0x4bdf15c3),
+       PCMCIA_MFC_DEVICE_PROD_ID12(0, "IBM", "w95 Home and Away Credit Card ", 0xb569a6e5, 0xae911c15),
+       PCMCIA_MFC_DEVICE_PROD_ID123(0, "APEX DATA", "MULTICARD", "ETHERNET-MODEM", 0x11c2da09, 0x7289dc5d, 0xaad95e1f),
+       PCMCIA_MFC_DEVICE_PROD_ID2(0, "FAX/Modem/Ethernet Combo Card ", 0x1ed59302),
+       PCMCIA_DEVICE_MANF_CARD(0x0057, 0x1004),
+       PCMCIA_DEVICE_MANF_CARD(0x0104, 0x000d),
+       PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0075),
+       PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0145),
+       PCMCIA_DEVICE_MANF_CARD(0x0149, 0x0230),
+       PCMCIA_DEVICE_MANF_CARD(0x0149, 0x4530),
+/*     PCMCIA_DEVICE_MANF_CARD(0x0149, 0xc1ab), conflict with axnet_cs */
+       PCMCIA_DEVICE_MANF_CARD(0x0186, 0x0110),
+       PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x2328),
+       PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x8041),
+       PCMCIA_DEVICE_MANF_CARD(0x0213, 0x2452),
+/*     PCMCIA_DEVICE_MANF_CARD(0x021b, 0x0202), conflict with axnet_cs */
+       PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0300),
+       PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0307),
+       PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030a),
+       PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1103),
+       PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1121),
+       PCMCIA_DEVICE_PROD_ID12("2408LAN", "Ethernet", 0x352fff7f, 0x00b2e941),
+       PCMCIA_DEVICE_PROD_ID123("Cardwell", "PCMCIA", "ETHERNET", 0x9533672e, 0x281f1c5d, 0x3ff7175b),
+       PCMCIA_DEVICE_PROD_ID123("CNet  ", "CN30BC", "ETHERNET", 0x9fe55d3d, 0x85601198, 0x3ff7175b),
+       PCMCIA_DEVICE_PROD_ID123("Digital", "Ethernet", "Adapter", 0x9999ab35, 0x00b2e941, 0x4b0d829e),
+       PCMCIA_DEVICE_PROD_ID123("Edimax Technology Inc.", "PCMCIA", "Ethernet Card", 0x738a0019, 0x281f1c5d, 0x5e9d92c0),
+       PCMCIA_DEVICE_PROD_ID123("EFA   ", "EFA207", "ETHERNET", 0x3d294be4, 0xeb9aab6c, 0x3ff7175b),
+       PCMCIA_DEVICE_PROD_ID123("I-O DATA", "PCLA", "ETHERNET", 0x1d55d7ec, 0xe4c64d34, 0x3ff7175b),
+       PCMCIA_DEVICE_PROD_ID123("IO DATA", "PCLATE", "ETHERNET", 0x547e66dc, 0x6b260753, 0x3ff7175b),
+       PCMCIA_DEVICE_PROD_ID123("KingMax Technology Inc.", "EN10-T2", "PCMCIA Ethernet Card", 0x932b7189, 0x699e4436, 0x6f6652e0),
+       PCMCIA_DEVICE_PROD_ID123("PCMCIA", "PCMCIA-ETHERNET-CARD", "UE2216", 0x281f1c5d, 0xd4cd2f20, 0xb87add82),
+       PCMCIA_DEVICE_PROD_ID123("PCMCIA", "PCMCIA-ETHERNET-CARD", "UE2620", 0x281f1c5d, 0xd4cd2f20, 0x7d3d83a8),
+       PCMCIA_DEVICE_PROD_ID1("2412LAN", 0x67f236ab),
+       PCMCIA_DEVICE_PROD_ID12("ACCTON", "EN2212", 0xdfc6b5b2, 0xcb112a11),
+       PCMCIA_DEVICE_PROD_ID12("ACCTON", "EN2216-PCMCIA-ETHERNET", 0xdfc6b5b2, 0x5542bfff),
+       PCMCIA_DEVICE_PROD_ID12("Allied Telesis, K.K.", "CentreCOM LA100-PCM-T V2 100/10M LAN PC Card", 0xbb7fbdd7, 0xcd91cc68),
+       PCMCIA_DEVICE_PROD_ID12("Allied Telesis, K.K.", "CentreCOM LA-PCM", 0xbb7fbdd7, 0x5ba10d49),
+       PCMCIA_DEVICE_PROD_ID12("Allied Telesis K.K.", "LA100-PCM V2", 0x36634a66, 0xc6d05997),
+       PCMCIA_DEVICE_PROD_ID12("Allied Telesis, K.K.", "CentreCOM LA-PCM_V2", 0xbb7fBdd7, 0x28e299f8),
+       PCMCIA_DEVICE_PROD_ID12("Allied Telesis K.K.", "LA-PCM V3", 0x36634a66, 0x62241d96),
+       PCMCIA_DEVICE_PROD_ID12("AmbiCom", "AMB8010", 0x5070a7f9, 0x82f96e96),
+       PCMCIA_DEVICE_PROD_ID12("AmbiCom", "AMB8610", 0x5070a7f9, 0x86741224),
+       PCMCIA_DEVICE_PROD_ID12("AmbiCom Inc", "AMB8002", 0x93b15570, 0x75ec3efb),
+       PCMCIA_DEVICE_PROD_ID12("AmbiCom Inc", "AMB8002T", 0x93b15570, 0x461c5247),
+       PCMCIA_DEVICE_PROD_ID12("AmbiCom Inc", "AMB8010", 0x93b15570, 0x82f96e96),
+       PCMCIA_DEVICE_PROD_ID12("AnyCom", "ECO Ethernet", 0x578ba6e7, 0x0a9888c1),
+       PCMCIA_DEVICE_PROD_ID12("AnyCom", "ECO Ethernet 10/100", 0x578ba6e7, 0x939fedbd),
+       PCMCIA_DEVICE_PROD_ID12("AROWANA", "PCMCIA Ethernet LAN Card", 0x313adbc8, 0x08d9f190),
+       PCMCIA_DEVICE_PROD_ID12("ASANTE", "FriendlyNet PC Card", 0x3a7ade0f, 0x41c64504),
+       PCMCIA_DEVICE_PROD_ID12("Billionton", "LNT-10TB", 0x552ab682, 0xeeb1ba6a),
+       PCMCIA_DEVICE_PROD_ID12("CF", "10Base-Ethernet", 0x44ebf863, 0x93ae4d79),
+       PCMCIA_DEVICE_PROD_ID12("CNet", "CN40BC Ethernet", 0xbc477dde, 0xfba775a7),
+       PCMCIA_DEVICE_PROD_ID12("COMPU-SHACK", "BASEline PCMCIA 10 MBit Ethernetadapter", 0xfa2e424d, 0xe9190d8a),
+       PCMCIA_DEVICE_PROD_ID12("COMPU-SHACK", "FASTline PCMCIA 10/100 Fast-Ethernet", 0xfa2e424d, 0x3953d9b9),
+       PCMCIA_DEVICE_PROD_ID12("CONTEC", "C-NET(PC)C-10L", 0x21cab552, 0xf6f90722),
+       PCMCIA_DEVICE_PROD_ID12("corega", "FEther PCC-TXF", 0x0a21501a, 0xa51564a2),
+       PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega EtherII PCC-T", 0x5261440f, 0xfa9d85bd),
+       PCMCIA_DEVICE_PROD_ID12("Corega K.K.", "corega EtherII PCC-TD", 0xd4fdcbd8, 0xc49bd73d),
+       PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega Ether PCC-T", 0x5261440f, 0x6705fcaa),
+       PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FastEther PCC-TX", 0x5261440f, 0x485e85d9),
+       PCMCIA_DEVICE_PROD_ID12("Corega,K.K.", "Ethernet LAN Card", 0x110d26d9, 0x9fd2f0a2),
+       PCMCIA_DEVICE_PROD_ID12("corega,K.K.", "Ethernet LAN Card", 0x9791a90e, 0x9fd2f0a2),
+       PCMCIA_DEVICE_PROD_ID12("CouplerlessPCMCIA", "100BASE", 0xee5af0ad, 0x7c2add04),
+       PCMCIA_DEVICE_PROD_ID12("CyQ've", "ELA-010", 0x77008979, 0x9d8d445d),
+       PCMCIA_DEVICE_PROD_ID12("CyQ've", "ELA-110E 10/100M LAN Card", 0x77008979, 0xfd184814),
+       PCMCIA_DEVICE_PROD_ID12("DataTrek.", "NetCard ", 0x5cd66d9d, 0x84697ce0),
+       PCMCIA_DEVICE_PROD_ID12("Dayna Communications, Inc.", "CommuniCard E", 0x0c629325, 0xb4e7dbaf),
+       PCMCIA_DEVICE_PROD_ID12("Digicom", "Palladio LAN 10/100", 0x697403d8, 0xe160b995),
+       PCMCIA_DEVICE_PROD_ID12("Digicom", "Palladio LAN 10/100 Dongless", 0x697403d8, 0xa6d3b233),
+       PCMCIA_DEVICE_PROD_ID12("DIGITAL", "DEPCM-XX", 0x69616cb3, 0xe600e76e),
+       PCMCIA_DEVICE_PROD_ID12("D-Link", "DE-650", 0x1a424a1c, 0xf28c8398),
+       PCMCIA_DEVICE_PROD_ID12("D-Link", "DE-660", 0x1a424a1c, 0xd9a1d05b),
+       PCMCIA_DEVICE_PROD_ID12("D-Link", "DFE-650", 0x1a424a1c, 0x0f0073f9),
+       PCMCIA_DEVICE_PROD_ID12("Dual Speed", "10/100 PC Card", 0x725b842d, 0xf1efee84),
+       PCMCIA_DEVICE_PROD_ID12("Dual Speed", "10/100 Port Attached PC Card", 0x725b842d, 0x2db1f8e9),
+       PCMCIA_DEVICE_PROD_ID12("Dynalink", "L10BC", 0x55632fd5, 0xdc65f2b1),
+       PCMCIA_DEVICE_PROD_ID12("DYNALINK", "L10BC", 0x6a26d1cf, 0xdc65f2b1),
+       PCMCIA_DEVICE_PROD_ID12("DYNALINK", "L10C", 0x6a26d1cf, 0xc4f84efb),
+       PCMCIA_DEVICE_PROD_ID12("E-CARD", "E-CARD", 0x6701da11, 0x6701da11),
+       PCMCIA_DEVICE_PROD_ID12("EIGER Labs Inc.", "Ethernet 10BaseT card", 0x53c864c6, 0xedd059f6),
+       PCMCIA_DEVICE_PROD_ID12("EIGER Labs Inc.", "Ethernet Combo card", 0x53c864c6, 0x929c486c),
+       PCMCIA_DEVICE_PROD_ID12("Ethernet", "Adapter", 0x00b2e941, 0x4b0d829e),
+       PCMCIA_DEVICE_PROD_ID12("Ethernet Adapter", "E2000 PCMCIA Ethernet", 0x96767301, 0x71fbbc61),
+       PCMCIA_DEVICE_PROD_ID12("Ethernet PCMCIA adapter", "EP-210", 0x8dd86181, 0xf2b52517),
+       PCMCIA_DEVICE_PROD_ID12("Fast Ethernet", "Adapter", 0xb4be14e3, 0x4b0d829e),
+       PCMCIA_DEVICE_PROD_ID12("Grey Cell", "GCS2000", 0x2a151fac, 0xf00555cb),
+       PCMCIA_DEVICE_PROD_ID12("Grey Cell", "GCS2220", 0x2a151fac, 0xc1b7e327),
+       PCMCIA_DEVICE_PROD_ID12("GVC", "NIC-2000p", 0x76e171bd, 0x6eb1c947),
+       PCMCIA_DEVICE_PROD_ID12("IBM Corp.", "Ethernet", 0xe3736c88, 0x00b2e941),
+       PCMCIA_DEVICE_PROD_ID12("IC-CARD", "IC-CARD", 0x60cb09a6, 0x60cb09a6),
+       PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCETTX", 0x547e66dc, 0x6fc5459b),
+       PCMCIA_DEVICE_PROD_ID12("iPort", "10/100 Ethernet Card", 0x56c538d2, 0x11b0ffc0),
+       PCMCIA_DEVICE_PROD_ID12("KANSAI ELECTRIC CO.,LTD", "KLA-PCM/T", 0xb18dc3b4, 0xcc51a956),
+       PCMCIA_DEVICE_PROD_ID12("KCI", "PE520 PCMCIA Ethernet Adapter", 0xa89b87d3, 0x1eb88e64),
+       PCMCIA_DEVICE_PROD_ID12("KINGMAX", "EN10T2T", 0x7bcb459a, 0xa5c81fa5),
+       PCMCIA_DEVICE_PROD_ID12("Kingston", "KNE-PC2", 0x1128e633, 0xce2a89b3),
+       PCMCIA_DEVICE_PROD_ID12("Kingston Technology Corp.", "EtheRx PC Card Ethernet Adapter", 0x313c7be3, 0x0afb54a2),
+       PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-10/100CD", 0x1b7827b2, 0xcda71d1c),
+       PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDF", 0x1b7827b2, 0xfec71e40),
+       PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDL/T", 0x1b7827b2, 0x79fba4f7),
+       PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDS", 0x1b7827b2, 0x931afaab),
+       PCMCIA_DEVICE_PROD_ID12("Linksys", "Combo PCMCIA EthernetCard (EC2T)", 0x0733cc81, 0x32ee8c78),
+       PCMCIA_DEVICE_PROD_ID12("LINKSYS", "E-CARD", 0xf7cb0b07, 0x6701da11),
+       PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 Integrated PC Card (PCM100)", 0x0733cc81, 0x453c3f9d),
+       PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 PC Card (PCMPC100)", 0x0733cc81, 0x66c5a389),
+       PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 PC Card (PCMPC100 V2)", 0x0733cc81, 0x3a3b28e9),
+       PCMCIA_DEVICE_PROD_ID12("Linksys", "HomeLink Phoneline ", 0x0733cc81, 0x5e07cfa0),
+       PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN100TX", 0x88fcdeda, 0x6d772737),
+       PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN20T", 0x88fcdeda, 0x81090922),
+       PCMCIA_DEVICE_PROD_ID12("LONGSHINE", "PCMCIA Ethernet Card", 0xf866b0b0, 0x6f6652e0),
+       PCMCIA_DEVICE_PROD_ID12("MACNICA", "ME1-JEIDA", 0x20841b68, 0xaf8a3578),
+       PCMCIA_DEVICE_PROD_ID12("Macsense", "MPC-10", 0xd830297f, 0xd265c307),
+       PCMCIA_DEVICE_PROD_ID12("Matsushita Electric Industrial Co.,LTD.", "CF-VEL211", 0x44445376, 0x8ded41d4),
+       PCMCIA_DEVICE_PROD_ID12("MAXTECH", "PCN2000", 0x78d64bc0, 0xca0ca4b8),
+       PCMCIA_DEVICE_PROD_ID12("MELCO", "LPC2-T", 0x481e0094, 0xa2eb0cf3),
+       PCMCIA_DEVICE_PROD_ID12("MELCO", "LPC2-TX", 0x481e0094, 0x41a6916c),
+       PCMCIA_DEVICE_PROD_ID12("Microcom C.E.", "Travel Card LAN 10/100", 0x4b91cec7, 0xe70220d6),
+       PCMCIA_DEVICE_PROD_ID12("Microdyne", "NE4200", 0x2e6da59b, 0x0478e472),
+       PCMCIA_DEVICE_PROD_ID12("MIDORI ELEC.", "LT-PCMT", 0x648d55c1, 0xbde526c7),
+       PCMCIA_DEVICE_PROD_ID12("National Semiconductor", "InfoMover 4100", 0x36e1191f, 0x60c229b9),
+       PCMCIA_DEVICE_PROD_ID12("National Semiconductor", "InfoMover NE4100", 0x36e1191f, 0xa6617ec8),
+       PCMCIA_DEVICE_PROD_ID12("NEC", "PC-9801N-J12", 0x18df0ba0, 0xbc912d76),
+       PCMCIA_DEVICE_PROD_ID12("NETGEAR", "FA410TX", 0x9aa79dc3, 0x60e5bc0e),
+       PCMCIA_DEVICE_PROD_ID12("NETGEAR", "FA411", 0x9aa79dc3, 0x40fad875),
+       PCMCIA_DEVICE_PROD_ID12("Network Everywhere", "Fast Ethernet 10/100 PC Card", 0x820a67b6, 0x31ed1a5f),
+       PCMCIA_DEVICE_PROD_ID12("NextCom K.K.", "Next Hawk", 0xaedaec74, 0xad050ef1),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "10/100Mbps Ethernet Card", 0x281f1c5d, 0x6e41773b),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Ethernet", 0x281f1c5d, 0x00b2e941),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "ETHERNET", 0x281f1c5d, 0x3ff7175b),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Ethernet 10BaseT Card", 0x281f1c5d, 0x4de2f6c8),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Ethernet Card", 0x281f1c5d, 0x5e9d92c0),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Ethernet Combo card", 0x281f1c5d, 0x929c486c),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "ETHERNET V1.0", 0x281f1c5d, 0x4d8817c8),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FastEthernet", 0x281f1c5d, 0xfe871eeb),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Fast-Ethernet", 0x281f1c5d, 0x45f1f3b4),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FAST ETHERNET CARD", 0x281f1c5d, 0xec5dbca7),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA LAN", "Ethernet", 0x7500e246, 0x00b2e941),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "LNT-10TN", 0x281f1c5d, 0xe707f641),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "UE2212", 0x281f1c5d, 0xbf17199b),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "    Ethernet NE2000 Compatible", 0x281f1c5d, 0x42d5d7e1),
+       PCMCIA_DEVICE_PROD_ID12("PRETEC", "Ethernet CompactLAN 10baseT 3.3V", 0xebf91155, 0x30074c80),
+       PCMCIA_DEVICE_PROD_ID12("PRETEC", "Ethernet CompactLAN 10BaseT 3.3V", 0xebf91155, 0x7f5a4f50),
+       PCMCIA_DEVICE_PROD_ID12("Psion Dacom", "Gold Card Ethernet", 0xf5f025c2, 0x3a30e110),
+       PCMCIA_DEVICE_PROD_ID12("=RELIA==", "Ethernet", 0xcdd0644a, 0x00b2e941),
+       PCMCIA_DEVICE_PROD_ID12("RP", "1625B Ethernet NE2000 Compatible", 0xe3e66e22, 0xb96150df),
+       PCMCIA_DEVICE_PROD_ID12("RPTI", "EP400 Ethernet NE2000 Compatible", 0xdc6f88fd, 0x4a7e2ae0),
+       PCMCIA_DEVICE_PROD_ID12("RPTI", "EP401 Ethernet NE2000 Compatible", 0xdc6f88fd, 0x4bcbd7fd),
+       PCMCIA_DEVICE_PROD_ID12("RPTI LTD.", "EP400", 0xc53ac515, 0x81e39388),
+       PCMCIA_DEVICE_PROD_ID12("SCM", "Ethernet Combo card", 0xbdc3b102, 0x929c486c),
+       PCMCIA_DEVICE_PROD_ID12("Seiko Epson Corp.", "Ethernet", 0x09928730, 0x00b2e941),
+       PCMCIA_DEVICE_PROD_ID12("SMC", "EZCard-10-PCMCIA", 0xc4f8b18b, 0xfb21d265),
+       PCMCIA_DEVICE_PROD_ID12("Socket Communications Inc", "Socket EA PCMCIA LAN Adapter Revision D", 0xc70a4760, 0x2ade483e),
+       PCMCIA_DEVICE_PROD_ID12("Socket Communications Inc", "Socket EA PCMCIA LAN Adapter Revision E", 0xc70a4760, 0x5dd978a8),
+       PCMCIA_DEVICE_PROD_ID12("TDK", "LAK-CD031 for PCMCIA", 0x1eae9475, 0x0ed386fa),
+       PCMCIA_DEVICE_PROD_ID12("Telecom Device K.K.", "SuperSocket RE450T", 0x466b05f0, 0x8b74bc4f),
+       PCMCIA_DEVICE_PROD_ID12("Telecom Device K.K.", "SuperSocket RE550T", 0x466b05f0, 0x33c8db2a),
+       PCMCIA_DEVICE_PROD_ID13("Hypertec",  "EP401", 0x8787bec7, 0xf6e4a31e),
+       PCMCIA_DEVICE_PROD_ID13("KingMax Technology Inc.", "Ethernet Card", 0x932b7189, 0x5e9d92c0),
+       PCMCIA_DEVICE_PROD_ID13("LONGSHINE", "EP401", 0xf866b0b0, 0xf6e4a31e),
+       PCMCIA_DEVICE_PROD_ID13("Xircom", "CFE-10", 0x2e3ee845, 0x22a49f89),
+       PCMCIA_DEVICE_PROD_ID1("CyQ've 10 Base-T LAN CARD", 0x94faf360),
+       PCMCIA_DEVICE_PROD_ID1("EP-210 PCMCIA LAN CARD.", 0x8850b4de),
+       PCMCIA_DEVICE_PROD_ID1("ETHER-C16", 0x06a8514f),
+       PCMCIA_DEVICE_PROD_ID1("IC-CARD", 0x60cb09a6),
+       PCMCIA_DEVICE_PROD_ID1("NE2000 Compatible", 0x75b8ad5a),
+       PCMCIA_DEVICE_PROD_ID2("EN-6200P2", 0xa996d078),
+       /* too generic! */
+       /* PCMCIA_DEVICE_PROD_ID12("PCMCIA", "10/100 Ethernet Card", 0x281f1c5d, 0x11b0ffc0), */
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "PCMCIA", "EN2218-LAN/MODEM", 0x281f1c5d, 0x570f348e, "PCMLM28.cis"),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "PCMCIA", "UE2218-LAN/MODEM", 0x281f1c5d, 0x6fdcacee, "PCMLM28.cis"),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "Psion Dacom", "Gold Card V34 Ethernet", 0xf5f025c2, 0x338e8155, "PCMLM28.cis"),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "Psion Dacom", "Gold Card V34 Ethernet GSM", 0xf5f025c2, 0x4ae85d35, "PCMLM28.cis"),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "LINKSYS", "PCMLM28", 0xf7cb0b07, 0x66881874, "PCMLM28.cis"),
+       PCMCIA_MFC_DEVICE_CIS_PROD_ID12(0, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "DP83903.cis"),
+       PCMCIA_MFC_DEVICE_CIS_PROD_ID4(0, "NSC MF LAN/Modem", 0x58fc6056, "DP83903.cis"),
+       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0175, 0x0000, "DP83903.cis"),
+       PCMCIA_DEVICE_CIS_MANF_CARD(0xc00f, 0x0002, "LA-PCM.cis"),
+       PCMCIA_DEVICE_CIS_PROD_ID12("KTI", "PE520 PLUS", 0xad180345, 0x9d58d392, "PE520.cis"),
+       PCMCIA_DEVICE_CIS_PROD_ID12("NDC", "Ethernet", 0x01c43ae1, 0x00b2e941, "NE2K.cis"),
+       PCMCIA_DEVICE_CIS_PROD_ID12("PMX   ", "PE-200", 0x34f3f1c8, 0x10b59f8c, "PE-200.cis"),
+       PCMCIA_DEVICE_CIS_PROD_ID12("TAMARACK", "Ethernet", 0xcf434fba, 0x00b2e941, "tamarack.cis"),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, pcnet_ids);
+
 static struct pcmcia_driver pcnet_driver = {
        .drv            = {
                .name   = "pcnet_cs",
@@ -1644,6 +1846,7 @@ static struct pcmcia_driver pcnet_driver = {
        .attach         = pcnet_attach,
        .detach         = pcnet_detach,
        .owner          = THIS_MODULE,
+       .id_table       = pcnet_ids,
 };
 
 static int __init init_pcnet_cs(void)
index 8a5e52c..bc01c88 100644 (file)
@@ -2327,6 +2327,38 @@ static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
        return rc;
 }
 
+static struct pcmcia_device_id smc91c92_ids[] = {
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0109, 0x0501),
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0140, 0x000a),
+       PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63),
+       PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63),
+       PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0xf510db04, 0x856d66c8, 0xbd6c43ef),
+       PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "XJEM1144/CCEM1144", "PCMCIA MODEM", 0xf510db04, 0x52d21e1e, 0xbd6c43ef),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard", 0x0c2f80cd, 0x0573c29f),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard", 0x0c2f80cd, 0x0573c29f),
+       PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x016c, 0x0020),
+       PCMCIA_DEVICE_MANF_CARD(0x016c, 0x0023),
+       PCMCIA_DEVICE_PROD_ID123("BASICS by New Media Corporation", "Ethernet", "SMC91C94", 0x23c78a9d, 0x00b2e941, 0xcef397fb),
+       PCMCIA_DEVICE_PROD_ID12("ARGOSY", "Fast Ethernet PCCard", 0x78f308dc, 0xdcea68bc),
+       PCMCIA_DEVICE_PROD_ID12("dit Co., Ltd.", "PC Card-10/100BTX", 0xe59365c8, 0x6a2161d1),
+       PCMCIA_DEVICE_PROD_ID12("DYNALINK", "L100C", 0x6a26d1cf, 0xc16ce9c5),
+       PCMCIA_DEVICE_PROD_ID12("Farallon", "Farallon Enet", 0x58d93fc4, 0x244734e9),
+       PCMCIA_DEVICE_PROD_ID12("Megahertz", "CC10BT/2", 0x33234748, 0x3c95b953),
+       PCMCIA_DEVICE_PROD_ID12("MELCO/SMC", "LPC-TX", 0xa2cd8e6d, 0x42da662a),
+       PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard", 0x0c2f80cd, 0x0573c29f),
+       PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard", 0x0c2f80cd, 0x0573c29f),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Fast Ethernet PCCard", 0x281f1c5d, 0xdcea68bc),
+       PCMCIA_DEVICE_PROD_ID12("Psion", "10Mb Ethernet", 0x4ef00b21, 0x844be9e9),
+       PCMCIA_DEVICE_PROD_ID12("SMC", "EtherEZ Ethernet 8020", 0xc4f8b18b, 0x4a0eeb2d),
+       /* These conflict with other cards! */
+       /* PCMCIA_DEVICE_MANF_CARD(0x0186, 0x0100), */
+       /* PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab), */
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, smc91c92_ids);
+
 static struct pcmcia_driver smc91c92_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -2334,6 +2366,7 @@ static struct pcmcia_driver smc91c92_cs_driver = {
        },
        .attach         = smc91c92_attach,
        .detach         = smc91c92_detach,
+       .id_table       = smc91c92_ids,
 };
 
 static int __init init_smc91c92_cs(void)
index 58177d6..0cd225e 100644 (file)
@@ -1983,6 +1983,33 @@ do_stop(struct net_device *dev)
     return 0;
 }
 
+static struct pcmcia_device_id xirc2ps_ids[] = {
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0089, 0x110a),
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0138, 0x110a),
+       PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "CEM28", 0x2e3ee845, 0x0ea978ea),
+       PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "CEM33", 0x2e3ee845, 0x80609023),
+       PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "CEM56", 0x2e3ee845, 0xa650c32a),
+       PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "REM10", 0x2e3ee845, 0x76df1d29),
+       PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "XEM5600", 0x2e3ee845, 0xf1403719),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "Xircom", "CreditCard Ethernet", 0x2e3ee845, 0xc0e778c2),
+       PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x010a),
+       PCMCIA_DEVICE_PROD_ID13("Toshiba Information Systems", "TPCENET", 0x1b3b94fe, 0xf381c1a2),
+       PCMCIA_DEVICE_PROD_ID13("Xircom", "CE3-10/100", 0x2e3ee845, 0x0ec0ac37),
+       PCMCIA_DEVICE_PROD_ID13("Xircom", "PS-CE2-10", 0x2e3ee845, 0x947d9073),
+       PCMCIA_DEVICE_PROD_ID13("Xircom", "R2E-100BTX", 0x2e3ee845, 0x2464a6e3),
+       PCMCIA_DEVICE_PROD_ID13("Xircom", "RE-10", 0x2e3ee845, 0x3e08d609),
+       PCMCIA_DEVICE_PROD_ID13("Xircom", "XE2000", 0x2e3ee845, 0xf7188e46),
+       PCMCIA_DEVICE_PROD_ID12("Compaq", "Ethernet LAN Card", 0x54f7c49c, 0x9fd2f0a2),
+       PCMCIA_DEVICE_PROD_ID12("Compaq", "Netelligent 10/100 PC Card", 0x54f7c49c, 0xefe96769),
+       PCMCIA_DEVICE_PROD_ID12("Intel", "EtherExpress(TM) PRO/100 PC Card Mobile Adapter16", 0x816cc815, 0x174397db),
+       PCMCIA_DEVICE_PROD_ID12("Toshiba", "10/100 Ethernet PC Card", 0x44a09d9c, 0xb44deecf),
+       /* also matches CFE-10 cards! */
+       /* PCMCIA_DEVICE_MANF_CARD(0x0105, 0x010a), */
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, xirc2ps_ids);
+
+
 static struct pcmcia_driver xirc2ps_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -1990,6 +2017,7 @@ static struct pcmcia_driver xirc2ps_cs_driver = {
        },
        .attach         = xirc2ps_attach,
        .detach         = xirc2ps_detach,
+       .id_table       = xirc2ps_ids,
 };
 
 static int __init
index fbf53af..f10a952 100644 (file)
@@ -559,6 +559,15 @@ static int airo_event(event_t event, int priority,
        return 0;
 } /* airo_event */
 
+static struct pcmcia_device_id airo_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(0x015f, 0x000a),
+       PCMCIA_DEVICE_MANF_CARD(0x015f, 0x0005),
+       PCMCIA_DEVICE_MANF_CARD(0x015f, 0x0007),
+       PCMCIA_DEVICE_MANF_CARD(0x0105, 0x0007),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, airo_ids);
+
 static struct pcmcia_driver airo_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -566,6 +575,7 @@ static struct pcmcia_driver airo_driver = {
        },
        .attach         = airo_attach,
        .detach         = airo_detach,
+       .id_table       = airo_ids,
 };
 
 static int airo_cs_init(void)
index a4ed28d..86379d4 100644 (file)
@@ -646,6 +646,27 @@ static int atmel_event(event_t event, int priority,
 } /* atmel_event */
 
 /*====================================================================*/
+static struct pcmcia_device_id atmel_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0620),
+       PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0696),
+       PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x3302),
+       PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0007),
+       PCMCIA_DEVICE_PROD_ID12("11WAVE", "11WP611AL-E", 0x9eb2da1f, 0xc9a0d3f9),
+       PCMCIA_DEVICE_PROD_ID12("ATMEL", "AT76C502AR", 0xabda4164, 0x41b37e1f),
+       PCMCIA_DEVICE_PROD_ID12("ATMEL", "AT76C504", 0xabda4164, 0x5040670a),
+       PCMCIA_DEVICE_PROD_ID12("ATMEL", "AT76C504A", 0xabda4164, 0xe15ed87f),
+       PCMCIA_DEVICE_PROD_ID12("BT", "Voyager 1020 Laptop Adapter", 0xae49b86a, 0x1e957cd5),
+       PCMCIA_DEVICE_PROD_ID12("CNet", "CNWLC 11Mbps Wireless PC Card V-5", 0xbc477dde, 0x502fae6b),
+       PCMCIA_DEVICE_PROD_ID12("IEEE 802.11b", "Wireless LAN PC Card", 0x5b878724, 0x122f1df6),
+       PCMCIA_DEVICE_PROD_ID12("OEM", "11Mbps Wireless LAN PC Card V-3", 0xfea54c90, 0x1c5b0f68),
+       PCMCIA_DEVICE_PROD_ID12("SMC", "2632W", 0xc4f8b18b, 0x30f38774),
+       PCMCIA_DEVICE_PROD_ID12("SMC", "2632W-V2", 0xc4f8b18b, 0x172d1377),
+       PCMCIA_DEVICE_PROD_ID12("Wireless", "PC", 0xa407ecdd, 0x556e4d7e),
+       PCMCIA_DEVICE_PROD_ID12("WLAN", "802.11b PC CARD", 0x575c516c, 0xb1f6dbc4),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, atmel_ids);
+
 static struct pcmcia_driver atmel_driver = {
         .owner          = THIS_MODULE,
         .drv            = {
@@ -653,6 +674,7 @@ static struct pcmcia_driver atmel_driver = {
         },
         .attach         = atmel_attach,
         .detach         = atmel_detach,
+       .id_table       = atmel_ids,
 };
 
 static int atmel_cs_init(void)
index 382241e..e12bd75 100644 (file)
@@ -1668,6 +1668,12 @@ static int netwave_close(struct net_device *dev) {
     return 0;
 }
 
+static struct pcmcia_device_id netwave_ids[] = {
+       PCMCIA_DEVICE_PROD_ID12("Xircom", "CreditCard Netwave", 0x2e3ee845, 0x54e28a28),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, netwave_ids);
+
 static struct pcmcia_driver netwave_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -1675,6 +1681,7 @@ static struct pcmcia_driver netwave_driver = {
        },
        .attach         = netwave_attach,
        .detach         = netwave_detach,
+       .id_table       = netwave_ids,
 };
 
 static int __init init_netwave_cs(void)
index 74a8227..597c458 100644 (file)
@@ -608,6 +608,56 @@ static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
        " (David Gibson <hermes@gibson.dropbear.id.au>, "
        "Pavel Roskin <proski@gnu.org>, et al)";
 
+static struct pcmcia_device_id orinoco_cs_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300),
+       PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0001),
+       PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002),
+       PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002),
+       PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a),
+       PCMCIA_DEVICE_MANF_CARD(0x0261, 0x0002),
+       PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0001),
+       PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0305),
+       PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613),
+       PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002),
+       PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0673),
+       PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002),
+       PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x0002),
+       PCMCIA_DEVICE_MANF_CARD(0x14ea, 0xb001),
+       PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300),
+       PCMCIA_DEVICE_MANF_CARD(0x9005, 0x0021),
+       PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002),
+       PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002),
+       PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002),
+       PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005),
+       PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005),
+       PCMCIA_DEVICE_PROD_ID12("3Com", "3CRWE737A AirConnect Wireless LAN PC Card", 0x41240e5b, 0x56010af3),
+       PCMCIA_DEVICE_PROD_ID123("Instant Wireless ", " Network PC CARD", "Version 01.02", 0x11d901af, 0x6e9bd926, 0x4b74baa0),
+       PCMCIA_DEVICE_PROD_ID12("ACTIONTEC", "PRISM Wireless LAN PC Card", 0x393089da, 0xa71e69d5),
+       PCMCIA_DEVICE_PROD_ID12("Avaya Communication", "Avaya Wireless PC Card", 0xd8a43b78, 0x0d341169),
+       PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-PCM-L11G", 0x2decece3, 0xf57ca4b3),
+       PCMCIA_DEVICE_PROD_ID12("Cabletron", "RoamAbout 802.11 DS", 0x32d445f5, 0xedeffd90),
+       PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCC-11", 0x5261440f, 0xa6405584),
+       PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCCA-11", 0x5261440f, 0xdf6115f9),
+       PCMCIA_DEVICE_PROD_ID12("D", "Link DRC-650 11Mbps WLAN Card", 0x71b18589, 0xf144e3ac),
+       PCMCIA_DEVICE_PROD_ID12("D", "Link DWL-650 11Mbps WLAN Card", 0x71b18589, 0xb6f1b0ab),
+       PCMCIA_DEVICE_PROD_ID12("ELSA", "AirLancer MC-11", 0x4507a33a, 0xef54f0e3),
+       PCMCIA_DEVICE_PROD_ID12("HyperLink", "Wireless PC Card 11Mbps", 0x56cc3f1a, 0x0bcf220c),
+       PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", 0x74c5e40d, 0xdb472a18),
+       PCMCIA_DEVICE_PROD_ID12("Lucent Technologies", "WaveLAN/IEEE", 0x23eb9949, 0xc562e72a),
+       PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11", 0x481e0094, 0x7360e410),
+       PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11G", 0x481e0094, 0xf57ca4b3),
+       PCMCIA_DEVICE_PROD_ID12("Microsoft", "Wireless Notebook Adapter MN-520", 0x5961bf85, 0x6eec8c01),
+       PCMCIA_DEVICE_PROD_ID12("NCR", "WaveLAN/IEEE", 0x24358cd4, 0xc562e72a),
+       PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401RA Wireless PC", "Card", 0x0306467f, 0x9762e8f1),
+       PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-CF110", 0x209f40ab, 0xd9715264),
+       PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PC CARD HARMONY 80211B", 0xc6536a5e, 0x090c3cd9),
+       PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PCI CARD HARMONY 80211B", 0xc6536a5e, 0x9f494e26),
+       PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "11Mbps WLAN Card", 0x43d74cb4, 0x579bd91b),
+       PCMCIA_DEVICE_PROD_ID1("Symbol Technologies", 0x3f02b4d6),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, orinoco_cs_ids);
+
 static struct pcmcia_driver orinoco_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -615,6 +665,7 @@ static struct pcmcia_driver orinoco_driver = {
        },
        .attach         = orinoco_cs_attach,
        .detach         = orinoco_cs_detach,
+       .id_table       = orinoco_cs_ids,
 };
 
 static int __init
index 6e5bda5..31652af 100644 (file)
@@ -2904,6 +2904,12 @@ static int write_int(struct file *file, const char __user *buffer, unsigned long
 }
 #endif
 
+static struct pcmcia_device_id ray_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(0x01a6, 0x0000),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, ray_ids);
+
 static struct pcmcia_driver ray_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -2911,6 +2917,7 @@ static struct pcmcia_driver ray_driver = {
        },
        .attach         = ray_attach,
        .detach         = ray_detach,
+       .id_table       = ray_ids,
 };
 
 static int __init init_ray_cs(void)
index ec83297..89532fd 100644 (file)
@@ -4889,6 +4889,15 @@ wavelan_event(event_t            event,          /* The event received */
   return 0;
 }
 
+static struct pcmcia_device_id wavelan_ids[] = {
+       PCMCIA_DEVICE_PROD_ID12("AT&T","WaveLAN/PCMCIA", 0xe7c5affd, 0x1bc50975),
+       PCMCIA_DEVICE_PROD_ID12("Digital", "RoamAbout/DS", 0x9999ab35, 0x00d05e06),
+       PCMCIA_DEVICE_PROD_ID12("Lucent Technologies", "WaveLAN/PCMCIA", 0x23eb9949, 0x1bc50975),
+       PCMCIA_DEVICE_PROD_ID12("NCR", "WaveLAN/PCMCIA", 0x24358cd4, 0x1bc50975),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, wavelan_ids);
+
 static struct pcmcia_driver wavelan_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -4896,6 +4905,7 @@ static struct pcmcia_driver wavelan_driver = {
        },
        .attach         = wavelan_attach,
        .detach         = wavelan_detach,
+       .id_table       = wavelan_ids,
 };
 
 static int __init
index 1433e5a..e3a9004 100644 (file)
@@ -2239,6 +2239,12 @@ static int wl3501_event(event_t event, int pri, event_callback_args_t *args)
        return 0;
 }
 
+static struct pcmcia_device_id wl3501_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0001),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, wl3501_ids);
+
 static struct pcmcia_driver wl3501_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -2246,6 +2252,7 @@ static struct pcmcia_driver wl3501_driver = {
        },
        .attach         = wl3501_attach,
        .detach         = wl3501_detach,
+       .id_table       = wl3501_ids,
 };
 
 static int __init wl3501_init_module(void)
index a3fa818..ff45662 100644 (file)
@@ -373,6 +373,13 @@ int parport_event(event_t event, int priority,
     return 0;
 } /* parport_event */
 
+static struct pcmcia_device_id parport_ids[] = {
+       PCMCIA_DEVICE_FUNC_ID(3),
+       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0003),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, parport_ids);
+
 static struct pcmcia_driver parport_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -380,6 +387,8 @@ static struct pcmcia_driver parport_cs_driver = {
        },
        .attach         = parport_attach,
        .detach         = parport_detach,
+       .id_table       = parport_ids,
+
 };
 
 static int __init init_parport_cs(void)
index 14e4124..52ea345 100644 (file)
@@ -14,8 +14,8 @@ config PCCARD
          Say Y here if you want to attach PCMCIA- or PC-cards to your Linux
          computer.  These are credit-card size devices such as network cards,
          modems or hard drives often used with laptops computers.  There are
-         actually two varieties of these cards: the older 16 bit PCMCIA cards
-         and the newer 32 bit CardBus cards.
+         actually two varieties of these cards: 16 bit PCMCIA and 32 bit
+         CardBus cards.
 
          To compile this driver as modules, choose M here: the
          module will be called pcmcia_core.
@@ -42,22 +42,51 @@ config PCMCIA_DEBUG
 
 config PCMCIA
        tristate "16-bit PCMCIA support"
+       select CRC32
        default y
        ---help---
           This option enables support for 16-bit PCMCIA cards. Most older
           PC-cards are such 16-bit PCMCIA cards, so unless you know you're
           only using 32-bit CardBus cards, say Y or M here.
 
-          To use 16-bit PCMCIA cards, you will need supporting software from 
-          David Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
-          for location).  Please also read the PCMCIA-HOWTO, available from
-          <http://www.tldp.org/docs.html#howto>.
+          To use 16-bit PCMCIA cards, you will need supporting software in
+          most cases. (see the file <file:Documentation/Changes> for
+          location and details).
 
           To compile this driver as modules, choose M here: the
           module will be called pcmcia.
 
           If unsure, say Y.
 
+config PCMCIA_LOAD_CIS
+       bool "Load CIS updates from userspace (EXPERIMENTAL)"
+       depends on PCMCIA && EXPERIMENTAL
+       select FW_LOADER
+       default y
+       help
+         Some PCMCIA cards require an updated Card Information Structure (CIS)
+         to be loaded from userspace to work correctly. If you say Y here,
+         and your userspace is arranged correctly, this will be loaded
+         automatically using the in-kernel firmware loader and the hotplug
+         subsystem, instead of relying on cardmgr from pcmcia-cs to do so.
+
+         If unsure, say Y.
+
+config PCMCIA_IOCTL
+       bool
+       depends on PCMCIA
+       default y
+       help
+         If you say Y here, the deprecated ioctl interface to the PCMCIA
+         subsystem will be built. It is needed by cardmgr and cardctl
+         (pcmcia-cs) to function properly.
+
+         If you do not use the new pcmciautils package, and have a
+         yenta, Cirrus PD6729, i82092, i82365 or tcic compatible bridge,
+         you need to say Y here to be able to use 16-bit PCMCIA cards.
+
+         If unsure, say Y.
+
 config CARDBUS
        bool "32-bit CardBus support"   
        depends on PCI
@@ -77,8 +106,6 @@ comment "PC-card bridges"
 
 config YENTA
        tristate "CardBus yenta-compatible bridge support"
-       depends on PCI
-#fixme: remove dependendcy on CARDBUS
        depends on CARDBUS
        select PCCARD_NONSTATIC
        ---help---
index 50c2936..ef694c7 100644 (file)
@@ -10,7 +10,8 @@ pcmcia_core-y                                 += cs.o cistpl.o rsrc_mgr.o socket_sysfs.o
 pcmcia_core-$(CONFIG_CARDBUS)                  += cardbus.o
 obj-$(CONFIG_PCCARD)                           += pcmcia_core.o
 
-pcmcia-y                                       += ds.o pcmcia_compat.o
+pcmcia-y                                       += ds.o pcmcia_compat.o pcmcia_resource.o
+pcmcia-$(CONFIG_PCMCIA_IOCTL)                  += pcmcia_ioctl.o
 obj-$(CONFIG_PCMCIA)                           += pcmcia.o
 
 obj-$(CONFIG_PCCARD_NONSTATIC)                 += rsrc_nonstatic.o
index e29a6dd..dd7651f 100644 (file)
@@ -89,8 +89,10 @@ static void __iomem *
 set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flags)
 {
     pccard_mem_map *mem = &s->cis_mem;
+    int ret;
+
     if (!(s->features & SS_CAP_STATIC_MAP) && mem->res == NULL) {
-       mem->res = find_mem_region(0, s->map_size, s->map_size, 0, s);
+       mem->res = pcmcia_find_mem_region(0, s->map_size, s->map_size, 0, s);
        if (mem->res == NULL) {
            printk(KERN_NOTICE "cs: unable to map card memory!\n");
            return NULL;
@@ -99,7 +101,12 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag
     }
     mem->card_start = card_offset;
     mem->flags = flags;
-    s->ops->set_mem_map(s, mem);
+    ret = s->ops->set_mem_map(s, mem);
+    if (ret) {
+       iounmap(s->cis_virt);
+       return NULL;
+    }
+
     if (s->features & SS_CAP_STATIC_MAP) {
        if (s->cis_virt)
            iounmap(s->cis_virt);
@@ -119,13 +126,13 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag
 #define IS_ATTR                1
 #define IS_INDIRECT    8
 
-int read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
+int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
                 u_int len, void *ptr)
 {
     void __iomem *sys, *end;
     unsigned char *buf = ptr;
     
-    cs_dbg(s, 3, "read_cis_mem(%d, %#x, %u)\n", attr, addr, len);
+    cs_dbg(s, 3, "pcmcia_read_cis_mem(%d, %#x, %u)\n", attr, addr, len);
 
     if (attr & IS_INDIRECT) {
        /* Indirect accesses use a bunch of special registers at fixed
@@ -182,14 +189,16 @@ int read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
          *(u_char *)(ptr+2), *(u_char *)(ptr+3));
     return 0;
 }
+EXPORT_SYMBOL(pcmcia_read_cis_mem);
+
 
-void write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
+void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
                   u_int len, void *ptr)
 {
     void __iomem *sys, *end;
     unsigned char *buf = ptr;
     
-    cs_dbg(s, 3, "write_cis_mem(%d, %#x, %u)\n", attr, addr, len);
+    cs_dbg(s, 3, "pcmcia_write_cis_mem(%d, %#x, %u)\n", attr, addr, len);
 
     if (attr & IS_INDIRECT) {
        /* Indirect accesses use a bunch of special registers at fixed
@@ -239,6 +248,8 @@ void write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
        }
     }
 }
+EXPORT_SYMBOL(pcmcia_write_cis_mem);
+
 
 /*======================================================================
 
@@ -274,7 +285,7 @@ static void read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr,
        ret = read_cb_mem(s, attr, addr, len, ptr);
     else
 #endif
-       ret = read_cis_mem(s, attr, addr, len, ptr);
+       ret = pcmcia_read_cis_mem(s, attr, addr, len, ptr);
 
        if (ret == 0) {
                /* Copy data into the cache */
@@ -348,7 +359,7 @@ int verify_cis_cache(struct pcmcia_socket *s)
                        read_cb_mem(s, cis->attr, cis->addr, len, buf);
                else
 #endif
-                       read_cis_mem(s, cis->attr, cis->addr, len, buf);
+                       pcmcia_read_cis_mem(s, cis->attr, cis->addr, len, buf);
 
                if (memcmp(buf, cis->cache, len) != 0) {
                        kfree(buf);
@@ -381,6 +392,7 @@ int pcmcia_replace_cis(struct pcmcia_socket *s, cisdump_t *cis)
     memcpy(s->fake_cis, cis->Data, cis->Length);
     return CS_SUCCESS;
 }
+EXPORT_SYMBOL(pcmcia_replace_cis);
 
 /*======================================================================
 
index 48e4f04..e82859d 100644 (file)
 #include <pcmcia/ds.h>
 #include "cs_internal.h"
 
-#ifdef CONFIG_PCI
-#define PCI_OPT " [pci]"
-#else
-#define PCI_OPT ""
-#endif
-#ifdef CONFIG_CARDBUS
-#define CB_OPT " [cardbus]"
-#else
-#define CB_OPT ""
-#endif
-#ifdef CONFIG_PM
-#define PM_OPT " [pm]"
-#else
-#define PM_OPT ""
-#endif
-#if !defined(CONFIG_CARDBUS) && !defined(CONFIG_PCI) && !defined(CONFIG_PM)
-#define OPTIONS " none"
-#else
-#define OPTIONS PCI_OPT CB_OPT PM_OPT
-#endif
-
-static const char *release = "Linux Kernel Card Services";
-static const char *options = "options: " OPTIONS;
-
-/*====================================================================*/
 
 /* Module parameters */
 
 MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
-MODULE_DESCRIPTION("Linux Kernel Card Services\noptions:" OPTIONS);
+MODULE_DESCRIPTION("Linux Kernel Card Services");
 MODULE_LICENSE("GPL");
 
 #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444)
@@ -89,9 +64,6 @@ INT_MODULE_PARM(unreset_limit,        30);            /* unreset_check's */
 /* Access speed for attribute memory windows */
 INT_MODULE_PARM(cis_speed,     300);           /* ns */
 
-/* Access speed for IO windows */
-INT_MODULE_PARM(io_speed,      0);             /* ns */
-
 #ifdef DEBUG
 static int pc_debug;
 
@@ -103,34 +75,26 @@ int cs_debug_level(int level)
 }
 #endif
 
-/*====================================================================*/
 
 socket_state_t dead_socket = {
        .csc_mask       = SS_DETECT,
 };
+EXPORT_SYMBOL(dead_socket);
 
 
 /* List of all sockets, protected by a rwsem */
 LIST_HEAD(pcmcia_socket_list);
-DECLARE_RWSEM(pcmcia_socket_list_rwsem);
 EXPORT_SYMBOL(pcmcia_socket_list);
-EXPORT_SYMBOL(pcmcia_socket_list_rwsem);
-
 
-#ifdef CONFIG_PCMCIA_PROBE
-/* mask ofIRQs already reserved by other cards, we should avoid using them */
-static u8 pcmcia_used_irq[NR_IRQS];
-#endif
+DECLARE_RWSEM(pcmcia_socket_list_rwsem);
+EXPORT_SYMBOL(pcmcia_socket_list_rwsem);
 
-/*====================================================================
-
-    Low-level PC Card interface drivers need to register with Card
-    Services using these calls.
-    
-======================================================================*/
 
 /**
- * socket drivers are expected to use the following callbacks in their 
+ * Low-level PCMCIA socket drivers need to register with the PCCard
+ * core using pcmcia_register_socket.
+ *
+ * socket drivers are expected to use the following callbacks in their
  * .drv struct:
  *  - pcmcia_socket_dev_suspend
  *  - pcmcia_socket_dev_resume
@@ -230,8 +194,8 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
        }
 
        /* try to obtain a socket number [yes, it gets ugly if we
-        * register more than 2^sizeof(unsigned int) pcmcia 
-        * sockets... but the socket number is deprecated 
+        * register more than 2^sizeof(unsigned int) pcmcia
+        * sockets... but the socket number is deprecated
         * anyways, so I don't care] */
        down_write(&pcmcia_socket_list_rwsem);
        if (list_empty(&pcmcia_socket_list))
@@ -340,54 +304,49 @@ struct pcmcia_socket * pcmcia_get_socket_by_nr(unsigned int nr)
 EXPORT_SYMBOL(pcmcia_get_socket_by_nr);
 
 
-/*======================================================================
-
-    socket_setup() and shutdown_socket() are called by the main event
-    handler when card insertion and removal events are received.
-    socket_setup() turns on socket power and resets the socket, in two stages.
-    shutdown_socket() unconfigures a socket and turns off socket power.
-
-======================================================================*/
-
+/**
+ * socket_setup() and shutdown_socket() are called by the main event
+ * handler when card insertion and removal events are received.
+ * socket_setup() turns on socket power and resets the socket, in two stages.
+ * shutdown_socket() unconfigures a socket and turns off socket power.
+ */
 static void shutdown_socket(struct pcmcia_socket *s)
 {
-    cs_dbg(s, 1, "shutdown_socket\n");
-
-    /* Blank out the socket state */
-    s->socket = dead_socket;
-    s->ops->init(s);
-    s->ops->set_socket(s, &s->socket);
-    s->irq.AssignedIRQ = s->irq.Config = 0;
-    s->lock_count = 0;
-    destroy_cis_cache(s);
+       cs_dbg(s, 1, "shutdown_socket\n");
+
+       /* Blank out the socket state */
+       s->socket = dead_socket;
+       s->ops->init(s);
+       s->ops->set_socket(s, &s->socket);
+       s->irq.AssignedIRQ = s->irq.Config = 0;
+       s->lock_count = 0;
+       destroy_cis_cache(s);
 #ifdef CONFIG_CARDBUS
-    cb_free(s);
+       cb_free(s);
 #endif
-    s->functions = 0;
-    if (s->config) {
-       kfree(s->config);
-       s->config = NULL;
-    }
-
-    {
-       int status;
-       s->ops->get_status(s, &status);
-       if (status & SS_POWERON) {
-               printk(KERN_ERR "PCMCIA: socket %p: *** DANGER *** unable to remove socket power\n", s);
+       s->functions = 0;
+       if (s->config) {
+               kfree(s->config);
+               s->config = NULL;
        }
-    }
-} /* shutdown_socket */
 
-/*======================================================================
+       {
+               int status;
+               s->ops->get_status(s, &status);
+               if (status & SS_POWERON) {
+                       printk(KERN_ERR "PCMCIA: socket %p: *** DANGER *** unable to remove socket power\n", s);
+               }
+       }
+} /* shutdown_socket */
 
-    The central event handler.  Send_event() sends an event to the
-    16-bit subsystem, which then calls the relevant device drivers.
-    Parse_events() interprets the event bits from
-    a card status change report.  Do_shutdown() handles the high
-    priority stuff associated with a card removal.
-    
-======================================================================*/
 
+/**
+ * The central event handler.  Send_event() sends an event to the
+ * 16-bit subsystem, which then calls the relevant device drivers.
+ * Parse_events() interprets the event bits from
+ * a card status change report.  Do_shutdown() handles the high
+ * priority stuff associated with a card removal.
+ */
 
 /* NOTE: send_event needs to be called with skt->sem held. */
 
@@ -746,420 +705,9 @@ void pcmcia_parse_events(struct pcmcia_socket *s, u_int events)
                wake_up(&s->thread_wait);
        }
 } /* pcmcia_parse_events */
+EXPORT_SYMBOL(pcmcia_parse_events);
 
 
-/*======================================================================
-
-    Special stuff for managing IO windows, because they are scarce.
-    
-======================================================================*/
-
-static int alloc_io_space(struct pcmcia_socket *s, u_int attr, ioaddr_t *base,
-                         ioaddr_t num, u_int lines)
-{
-    int i;
-    kio_addr_t try, align;
-
-    align = (*base) ? (lines ? 1<<lines : 0) : 1;
-    if (align && (align < num)) {
-       if (*base) {
-           cs_dbg(s, 0, "odd IO request: num %#x align %#lx\n",
-                  num, align);
-           align = 0;
-       } else
-           while (align && (align < num)) align <<= 1;
-    }
-    if (*base & ~(align-1)) {
-       cs_dbg(s, 0, "odd IO request: base %#x align %#lx\n",
-              *base, align);
-       align = 0;
-    }
-    if ((s->features & SS_CAP_STATIC_MAP) && s->io_offset) {
-       *base = s->io_offset | (*base & 0x0fff);
-       return 0;
-    }
-    /* Check for an already-allocated window that must conflict with
-       what was asked for.  It is a hack because it does not catch all
-       potential conflicts, just the most obvious ones. */
-    for (i = 0; i < MAX_IO_WIN; i++)
-       if ((s->io[i].NumPorts != 0) &&
-           ((s->io[i].BasePort & (align-1)) == *base))
-           return 1;
-    for (i = 0; i < MAX_IO_WIN; i++) {
-       if (s->io[i].NumPorts == 0) {
-           s->io[i].res = find_io_region(*base, num, align, s);
-           if (s->io[i].res) {
-               s->io[i].Attributes = attr;
-               s->io[i].BasePort = *base = s->io[i].res->start;
-               s->io[i].NumPorts = s->io[i].InUse = num;
-               break;
-           } else
-               return 1;
-       } else if (s->io[i].Attributes != attr)
-           continue;
-       /* Try to extend top of window */
-       try = s->io[i].BasePort + s->io[i].NumPorts;
-       if ((*base == 0) || (*base == try))
-           if (adjust_io_region(s->io[i].res, s->io[i].res->start,
-                                s->io[i].res->end + num, s) == 0) {
-               *base = try;
-               s->io[i].NumPorts += num;
-               s->io[i].InUse += num;
-               break;
-           }
-       /* Try to extend bottom of window */
-       try = s->io[i].BasePort - num;
-       if ((*base == 0) || (*base == try))
-           if (adjust_io_region(s->io[i].res, s->io[i].res->start - num,
-                                s->io[i].res->end, s) == 0) {
-               s->io[i].BasePort = *base = try;
-               s->io[i].NumPorts += num;
-               s->io[i].InUse += num;
-               break;
-           }
-    }
-    return (i == MAX_IO_WIN);
-} /* alloc_io_space */
-
-static void release_io_space(struct pcmcia_socket *s, ioaddr_t base,
-                            ioaddr_t num)
-{
-    int i;
-
-    for (i = 0; i < MAX_IO_WIN; i++) {
-       if ((s->io[i].BasePort <= base) &&
-           (s->io[i].BasePort+s->io[i].NumPorts >= base+num)) {
-           s->io[i].InUse -= num;
-           /* Free the window if no one else is using it */
-           if (s->io[i].InUse == 0) {
-               s->io[i].NumPorts = 0;
-               release_resource(s->io[i].res);
-               kfree(s->io[i].res);
-               s->io[i].res = NULL;
-           }
-       }
-    }
-}
-
-/*======================================================================
-
-    Access_configuration_register() reads and writes configuration
-    registers in attribute memory.  Memory window 0 is reserved for
-    this and the tuple reading services.
-    
-======================================================================*/
-
-int pccard_access_configuration_register(struct pcmcia_socket *s,
-                                        unsigned int function,
-                                        conf_reg_t *reg)
-{
-    config_t *c;
-    int addr;
-    u_char val;
-
-    if (!s || !s->config)
-       return CS_NO_CARD;    
-
-    c = &s->config[function];
-
-    if (c == NULL)
-       return CS_NO_CARD;
-
-    if (!(c->state & CONFIG_LOCKED))
-       return CS_CONFIGURATION_LOCKED;
-
-    addr = (c->ConfigBase + reg->Offset) >> 1;
-    
-    switch (reg->Action) {
-    case CS_READ:
-       read_cis_mem(s, 1, addr, 1, &val);
-       reg->Value = val;
-       break;
-    case CS_WRITE:
-       val = reg->Value;
-       write_cis_mem(s, 1, addr, 1, &val);
-       break;
-    default:
-       return CS_BAD_ARGS;
-       break;
-    }
-    return CS_SUCCESS;
-} /* access_configuration_register */
-EXPORT_SYMBOL(pccard_access_configuration_register);
-
-
-/*====================================================================*/
-
-int pccard_get_configuration_info(struct pcmcia_socket *s,
-                                 unsigned int function,
-                                 config_info_t *config)
-{
-    config_t *c;
-    
-    if (!(s->state & SOCKET_PRESENT))
-       return CS_NO_CARD;
-
-    config->Function = function;
-
-#ifdef CONFIG_CARDBUS
-    if (s->state & SOCKET_CARDBUS) {
-       memset(config, 0, sizeof(config_info_t));
-       config->Vcc = s->socket.Vcc;
-       config->Vpp1 = config->Vpp2 = s->socket.Vpp;
-       config->Option = s->cb_dev->subordinate->number;
-       if (s->state & SOCKET_CARDBUS_CONFIG) {
-           config->Attributes = CONF_VALID_CLIENT;
-           config->IntType = INT_CARDBUS;
-           config->AssignedIRQ = s->irq.AssignedIRQ;
-           if (config->AssignedIRQ)
-               config->Attributes |= CONF_ENABLE_IRQ;
-           config->BasePort1 = s->io[0].BasePort;
-           config->NumPorts1 = s->io[0].NumPorts;
-       }
-       return CS_SUCCESS;
-    }
-#endif
-    
-    c = (s->config != NULL) ? &s->config[function] : NULL;
-    
-    if ((c == NULL) || !(c->state & CONFIG_LOCKED)) {
-       config->Attributes = 0;
-       config->Vcc = s->socket.Vcc;
-       config->Vpp1 = config->Vpp2 = s->socket.Vpp;
-       return CS_SUCCESS;
-    }
-    
-    /* !!! This is a hack !!! */
-    memcpy(&config->Attributes, &c->Attributes, sizeof(config_t));
-    config->Attributes |= CONF_VALID_CLIENT;
-    config->CardValues = c->CardValues;
-    config->IRQAttributes = c->irq.Attributes;
-    config->AssignedIRQ = s->irq.AssignedIRQ;
-    config->BasePort1 = c->io.BasePort1;
-    config->NumPorts1 = c->io.NumPorts1;
-    config->Attributes1 = c->io.Attributes1;
-    config->BasePort2 = c->io.BasePort2;
-    config->NumPorts2 = c->io.NumPorts2;
-    config->Attributes2 = c->io.Attributes2;
-    config->IOAddrLines = c->io.IOAddrLines;
-    
-    return CS_SUCCESS;
-} /* get_configuration_info */
-EXPORT_SYMBOL(pccard_get_configuration_info);
-
-/*======================================================================
-
-    Return information about this version of Card Services.
-    
-======================================================================*/
-
-int pcmcia_get_card_services_info(servinfo_t *info)
-{
-    unsigned int socket_count = 0;
-    struct list_head *tmp;
-    info->Signature[0] = 'C';
-    info->Signature[1] = 'S';
-    down_read(&pcmcia_socket_list_rwsem);
-    list_for_each(tmp, &pcmcia_socket_list)
-           socket_count++;
-    up_read(&pcmcia_socket_list_rwsem);
-    info->Count = socket_count;
-    info->Revision = CS_RELEASE_CODE;
-    info->CSLevel = 0x0210;
-    info->VendorString = (char *)release;
-    return CS_SUCCESS;
-} /* get_card_services_info */
-
-
-/*====================================================================*/
-
-int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *handle, int idx, win_req_t *req)
-{
-    window_t *win;
-    int w;
-
-    if (!s || !(s->state & SOCKET_PRESENT))
-       return CS_NO_CARD;
-    for (w = idx; w < MAX_WIN; w++)
-       if (s->state & SOCKET_WIN_REQ(w)) break;
-    if (w == MAX_WIN)
-       return CS_NO_MORE_ITEMS;
-    win = &s->win[w];
-    req->Base = win->ctl.res->start;
-    req->Size = win->ctl.res->end - win->ctl.res->start + 1;
-    req->AccessSpeed = win->ctl.speed;
-    req->Attributes = 0;
-    if (win->ctl.flags & MAP_ATTRIB)
-       req->Attributes |= WIN_MEMORY_TYPE_AM;
-    if (win->ctl.flags & MAP_ACTIVE)
-       req->Attributes |= WIN_ENABLE;
-    if (win->ctl.flags & MAP_16BIT)
-       req->Attributes |= WIN_DATA_WIDTH_16;
-    if (win->ctl.flags & MAP_USE_WAIT)
-       req->Attributes |= WIN_USE_WAIT;
-    *handle = win;
-    return CS_SUCCESS;
-} /* get_window */
-EXPORT_SYMBOL(pcmcia_get_window);
-
-/*=====================================================================
-
-    Return the PCI device associated with a card..
-
-======================================================================*/
-
-#ifdef CONFIG_CARDBUS
-
-struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s)
-{
-       if (!s || !(s->state & SOCKET_CARDBUS))
-               return NULL;
-
-       return s->cb_dev->subordinate;
-}
-
-EXPORT_SYMBOL(pcmcia_lookup_bus);
-
-#endif
-
-/*======================================================================
-
-    Get the current socket state bits.  We don't support the latched
-    SocketState yet: I haven't seen any point for it.
-    
-======================================================================*/
-
-int pccard_get_status(struct pcmcia_socket *s, unsigned int function, cs_status_t *status)
-{
-    config_t *c;
-    int val;
-    
-    s->ops->get_status(s, &val);
-    status->CardState = status->SocketState = 0;
-    status->CardState |= (val & SS_DETECT) ? CS_EVENT_CARD_DETECT : 0;
-    status->CardState |= (val & SS_CARDBUS) ? CS_EVENT_CB_DETECT : 0;
-    status->CardState |= (val & SS_3VCARD) ? CS_EVENT_3VCARD : 0;
-    status->CardState |= (val & SS_XVCARD) ? CS_EVENT_XVCARD : 0;
-    if (s->state & SOCKET_SUSPEND)
-       status->CardState |= CS_EVENT_PM_SUSPEND;
-    if (!(s->state & SOCKET_PRESENT))
-       return CS_NO_CARD;
-    
-    c = (s->config != NULL) ? &s->config[function] : NULL;
-    if ((c != NULL) && (c->state & CONFIG_LOCKED) &&
-       (c->IntType & (INT_MEMORY_AND_IO | INT_ZOOMED_VIDEO))) {
-       u_char reg;
-       if (c->Present & PRESENT_PIN_REPLACE) {
-           read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, &reg);
-           status->CardState |=
-               (reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0;
-           status->CardState |=
-               (reg & PRR_READY_STATUS) ? CS_EVENT_READY_CHANGE : 0;
-           status->CardState |=
-               (reg & PRR_BVD2_STATUS) ? CS_EVENT_BATTERY_LOW : 0;
-           status->CardState |=
-               (reg & PRR_BVD1_STATUS) ? CS_EVENT_BATTERY_DEAD : 0;
-       } else {
-           /* No PRR?  Then assume we're always ready */
-           status->CardState |= CS_EVENT_READY_CHANGE;
-       }
-       if (c->Present & PRESENT_EXT_STATUS) {
-           read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, &reg);
-           status->CardState |=
-               (reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0;
-       }
-       return CS_SUCCESS;
-    }
-    status->CardState |=
-       (val & SS_WRPROT) ? CS_EVENT_WRITE_PROTECT : 0;
-    status->CardState |=
-       (val & SS_BATDEAD) ? CS_EVENT_BATTERY_DEAD : 0;
-    status->CardState |=
-       (val & SS_BATWARN) ? CS_EVENT_BATTERY_LOW : 0;
-    status->CardState |=
-       (val & SS_READY) ? CS_EVENT_READY_CHANGE : 0;
-    return CS_SUCCESS;
-} /* get_status */
-EXPORT_SYMBOL(pccard_get_status);
-
-/*======================================================================
-
-    Change the card address of an already open memory window.
-    
-======================================================================*/
-
-int pcmcia_get_mem_page(window_handle_t win, memreq_t *req)
-{
-    if ((win == NULL) || (win->magic != WINDOW_MAGIC))
-       return CS_BAD_HANDLE;
-    req->Page = 0;
-    req->CardOffset = win->ctl.card_start;
-    return CS_SUCCESS;
-} /* get_mem_page */
-
-int pcmcia_map_mem_page(window_handle_t win, memreq_t *req)
-{
-    struct pcmcia_socket *s;
-    if ((win == NULL) || (win->magic != WINDOW_MAGIC))
-       return CS_BAD_HANDLE;
-    if (req->Page != 0)
-       return CS_BAD_PAGE;
-    s = win->sock;
-    win->ctl.card_start = req->CardOffset;
-    if (s->ops->set_mem_map(s, &win->ctl) != 0)
-       return CS_BAD_OFFSET;
-    return CS_SUCCESS;
-} /* map_mem_page */
-
-/*======================================================================
-
-    Modify a locked socket configuration
-    
-======================================================================*/
-
-int pcmcia_modify_configuration(client_handle_t handle,
-                               modconf_t *mod)
-{
-    struct pcmcia_socket *s;
-    config_t *c;
-    
-    if (CHECK_HANDLE(handle))
-       return CS_BAD_HANDLE;
-    s = SOCKET(handle); c = CONFIG(handle);
-    if (!(s->state & SOCKET_PRESENT))
-       return CS_NO_CARD;
-    if (!(c->state & CONFIG_LOCKED))
-       return CS_CONFIGURATION_LOCKED;
-    
-    if (mod->Attributes & CONF_IRQ_CHANGE_VALID) {
-       if (mod->Attributes & CONF_ENABLE_IRQ) {
-           c->Attributes |= CONF_ENABLE_IRQ;
-           s->socket.io_irq = s->irq.AssignedIRQ;
-       } else {
-           c->Attributes &= ~CONF_ENABLE_IRQ;
-           s->socket.io_irq = 0;
-       }
-       s->ops->set_socket(s, &s->socket);
-    }
-
-    if (mod->Attributes & CONF_VCC_CHANGE_VALID)
-       return CS_BAD_VCC;
-
-    /* We only allow changing Vpp1 and Vpp2 to the same value */
-    if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) &&
-       (mod->Attributes & CONF_VPP2_CHANGE_VALID)) {
-       if (mod->Vpp1 != mod->Vpp2)
-           return CS_BAD_VPP;
-       c->Vpp1 = c->Vpp2 = s->socket.Vpp = mod->Vpp1;
-       if (s->ops->set_socket(s, &s->socket))
-           return CS_BAD_VPP;
-    } else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) ||
-              (mod->Attributes & CONF_VPP2_CHANGE_VALID))
-       return CS_BAD_VPP;
-
-    return CS_SUCCESS;
-} /* modify_configuration */
-
 /* register pcmcia_callback */
 int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c)
 {
@@ -1188,543 +736,16 @@ int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c)
 }
 EXPORT_SYMBOL(pccard_register_pcmcia);
 
-/*====================================================================*/
 
-int pcmcia_release_configuration(client_handle_t handle)
-{
-    pccard_io_map io = { 0, 0, 0, 0, 1 };
-    struct pcmcia_socket *s;
-    int i;
-    
-    if (CHECK_HANDLE(handle) ||
-       !(handle->state & CLIENT_CONFIG_LOCKED))
-       return CS_BAD_HANDLE;
-    handle->state &= ~CLIENT_CONFIG_LOCKED;
-    s = SOCKET(handle);
-    
-#ifdef CONFIG_CARDBUS
-    if (handle->state & CLIENT_CARDBUS)
-       return CS_SUCCESS;
-#endif
-    
-    if (!(handle->state & CLIENT_STALE)) {
-       config_t *c = CONFIG(handle);
-       if (--(s->lock_count) == 0) {
-           s->socket.flags = SS_OUTPUT_ENA;   /* Is this correct? */
-           s->socket.Vpp = 0;
-           s->socket.io_irq = 0;
-           s->ops->set_socket(s, &s->socket);
-       }
-       if (c->state & CONFIG_IO_REQ)
-           for (i = 0; i < MAX_IO_WIN; i++) {
-               if (s->io[i].NumPorts == 0)
-                   continue;
-               s->io[i].Config--;
-               if (s->io[i].Config != 0)
-                   continue;
-               io.map = i;
-               s->ops->set_io_map(s, &io);
-           }
-       c->state &= ~CONFIG_LOCKED;
-    }
-    
-    return CS_SUCCESS;
-} /* release_configuration */
-
-/*======================================================================
-
-    Release_io() releases the I/O ranges allocated by a client.  This
-    may be invoked some time after a card ejection has already dumped
-    the actual socket configuration, so if the client is "stale", we
-    don't bother checking the port ranges against the current socket
-    values.
-    
-======================================================================*/
-
-int pcmcia_release_io(client_handle_t handle, io_req_t *req)
-{
-    struct pcmcia_socket *s;
-    
-    if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IO_REQ))
-       return CS_BAD_HANDLE;
-    handle->state &= ~CLIENT_IO_REQ;
-    s = SOCKET(handle);
-    
-#ifdef CONFIG_CARDBUS
-    if (handle->state & CLIENT_CARDBUS)
-       return CS_SUCCESS;
-#endif
-    
-    if (!(handle->state & CLIENT_STALE)) {
-       config_t *c = CONFIG(handle);
-       if (c->state & CONFIG_LOCKED)
-           return CS_CONFIGURATION_LOCKED;
-       if ((c->io.BasePort1 != req->BasePort1) ||
-           (c->io.NumPorts1 != req->NumPorts1) ||
-           (c->io.BasePort2 != req->BasePort2) ||
-           (c->io.NumPorts2 != req->NumPorts2))
-           return CS_BAD_ARGS;
-       c->state &= ~CONFIG_IO_REQ;
-    }
-
-    release_io_space(s, req->BasePort1, req->NumPorts1);
-    if (req->NumPorts2)
-       release_io_space(s, req->BasePort2, req->NumPorts2);
-    
-    return CS_SUCCESS;
-} /* release_io */
-
-/*====================================================================*/
-
-int pcmcia_release_irq(client_handle_t handle, irq_req_t *req)
-{
-    struct pcmcia_socket *s;
-    if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IRQ_REQ))
-       return CS_BAD_HANDLE;
-    handle->state &= ~CLIENT_IRQ_REQ;
-    s = SOCKET(handle);
-    
-    if (!(handle->state & CLIENT_STALE)) {
-       config_t *c = CONFIG(handle);
-       if (c->state & CONFIG_LOCKED)
-           return CS_CONFIGURATION_LOCKED;
-       if (c->irq.Attributes != req->Attributes)
-           return CS_BAD_ATTRIBUTE;
-       if (s->irq.AssignedIRQ != req->AssignedIRQ)
-           return CS_BAD_IRQ;
-       if (--s->irq.Config == 0) {
-           c->state &= ~CONFIG_IRQ_REQ;
-           s->irq.AssignedIRQ = 0;
-       }
-    }
-    
-    if (req->Attributes & IRQ_HANDLE_PRESENT) {
-       free_irq(req->AssignedIRQ, req->Instance);
-    }
-
-#ifdef CONFIG_PCMCIA_PROBE
-    pcmcia_used_irq[req->AssignedIRQ]--;
-#endif
-
-    return CS_SUCCESS;
-} /* cs_release_irq */
-
-/*====================================================================*/
-
-int pcmcia_release_window(window_handle_t win)
-{
-    struct pcmcia_socket *s;
-    
-    if ((win == NULL) || (win->magic != WINDOW_MAGIC))
-       return CS_BAD_HANDLE;
-    s = win->sock;
-    if (!(win->handle->state & CLIENT_WIN_REQ(win->index)))
-       return CS_BAD_HANDLE;
-
-    /* Shut down memory window */
-    win->ctl.flags &= ~MAP_ACTIVE;
-    s->ops->set_mem_map(s, &win->ctl);
-    s->state &= ~SOCKET_WIN_REQ(win->index);
-
-    /* Release system memory */
-    if (win->ctl.res) {
-       release_resource(win->ctl.res);
-       kfree(win->ctl.res);
-       win->ctl.res = NULL;
-    }
-    win->handle->state &= ~CLIENT_WIN_REQ(win->index);
-
-    win->magic = 0;
-    
-    return CS_SUCCESS;
-} /* release_window */
-
-/*====================================================================*/
-
-int pcmcia_request_configuration(client_handle_t handle,
-                                config_req_t *req)
-{
-    int i;
-    u_int base;
-    struct pcmcia_socket *s;
-    config_t *c;
-    pccard_io_map iomap;
-    
-    if (CHECK_HANDLE(handle))
-       return CS_BAD_HANDLE;
-    s = SOCKET(handle);
-    if (!(s->state & SOCKET_PRESENT))
-       return CS_NO_CARD;
-    
-#ifdef CONFIG_CARDBUS
-    if (handle->state & CLIENT_CARDBUS)
-       return CS_UNSUPPORTED_MODE;
-#endif
-    
-    if (req->IntType & INT_CARDBUS)
-       return CS_UNSUPPORTED_MODE;
-    c = CONFIG(handle);
-    if (c->state & CONFIG_LOCKED)
-       return CS_CONFIGURATION_LOCKED;
-
-    /* Do power control.  We don't allow changes in Vcc. */
-    if (s->socket.Vcc != req->Vcc)
-       return CS_BAD_VCC;
-    if (req->Vpp1 != req->Vpp2)
-       return CS_BAD_VPP;
-    s->socket.Vpp = req->Vpp1;
-    if (s->ops->set_socket(s, &s->socket))
-       return CS_BAD_VPP;
-    
-    c->Vcc = req->Vcc; c->Vpp1 = c->Vpp2 = req->Vpp1;
-    
-    /* Pick memory or I/O card, DMA mode, interrupt */
-    c->IntType = req->IntType;
-    c->Attributes = req->Attributes;
-    if (req->IntType & INT_MEMORY_AND_IO)
-       s->socket.flags |= SS_IOCARD;
-    if (req->IntType & INT_ZOOMED_VIDEO)
-       s->socket.flags |= SS_ZVCARD | SS_IOCARD;
-    if (req->Attributes & CONF_ENABLE_DMA)
-       s->socket.flags |= SS_DMA_MODE;
-    if (req->Attributes & CONF_ENABLE_SPKR)
-       s->socket.flags |= SS_SPKR_ENA;
-    if (req->Attributes & CONF_ENABLE_IRQ)
-       s->socket.io_irq = s->irq.AssignedIRQ;
-    else
-       s->socket.io_irq = 0;
-    s->ops->set_socket(s, &s->socket);
-    s->lock_count++;
-    
-    /* Set up CIS configuration registers */
-    base = c->ConfigBase = req->ConfigBase;
-    c->Present = c->CardValues = req->Present;
-    if (req->Present & PRESENT_COPY) {
-       c->Copy = req->Copy;
-       write_cis_mem(s, 1, (base + CISREG_SCR)>>1, 1, &c->Copy);
-    }
-    if (req->Present & PRESENT_OPTION) {
-       if (s->functions == 1) {
-           c->Option = req->ConfigIndex & COR_CONFIG_MASK;
-       } else {
-           c->Option = req->ConfigIndex & COR_MFC_CONFIG_MASK;
-           c->Option |= COR_FUNC_ENA|COR_IREQ_ENA;
-           if (req->Present & PRESENT_IOBASE_0)
-               c->Option |= COR_ADDR_DECODE;
-       }
-       if (c->state & CONFIG_IRQ_REQ)
-           if (!(c->irq.Attributes & IRQ_FORCED_PULSE))
-               c->Option |= COR_LEVEL_REQ;
-       write_cis_mem(s, 1, (base + CISREG_COR)>>1, 1, &c->Option);
-       mdelay(40);
-    }
-    if (req->Present & PRESENT_STATUS) {
-       c->Status = req->Status;
-       write_cis_mem(s, 1, (base + CISREG_CCSR)>>1, 1, &c->Status);
-    }
-    if (req->Present & PRESENT_PIN_REPLACE) {
-       c->Pin = req->Pin;
-       write_cis_mem(s, 1, (base + CISREG_PRR)>>1, 1, &c->Pin);
-    }
-    if (req->Present & PRESENT_EXT_STATUS) {
-       c->ExtStatus = req->ExtStatus;
-       write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1, &c->ExtStatus);
-    }
-    if (req->Present & PRESENT_IOBASE_0) {
-       u_char b = c->io.BasePort1 & 0xff;
-       write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &b);
-       b = (c->io.BasePort1 >> 8) & 0xff;
-       write_cis_mem(s, 1, (base + CISREG_IOBASE_1)>>1, 1, &b);
-    }
-    if (req->Present & PRESENT_IOSIZE) {
-       u_char b = c->io.NumPorts1 + c->io.NumPorts2 - 1;
-       write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &b);
-    }
-    
-    /* Configure I/O windows */
-    if (c->state & CONFIG_IO_REQ) {
-       iomap.speed = io_speed;
-       for (i = 0; i < MAX_IO_WIN; i++)
-           if (s->io[i].NumPorts != 0) {
-               iomap.map = i;
-               iomap.flags = MAP_ACTIVE;
-               switch (s->io[i].Attributes & IO_DATA_PATH_WIDTH) {
-               case IO_DATA_PATH_WIDTH_16:
-                   iomap.flags |= MAP_16BIT; break;
-               case IO_DATA_PATH_WIDTH_AUTO:
-                   iomap.flags |= MAP_AUTOSZ; break;
-               default:
-                   break;
-               }
-               iomap.start = s->io[i].BasePort;
-               iomap.stop = iomap.start + s->io[i].NumPorts - 1;
-               s->ops->set_io_map(s, &iomap);
-               s->io[i].Config++;
-           }
-    }
-    
-    c->state |= CONFIG_LOCKED;
-    handle->state |= CLIENT_CONFIG_LOCKED;
-    return CS_SUCCESS;
-} /* request_configuration */
-
-/*======================================================================
-  
-    Request_io() reserves ranges of port addresses for a socket.
-    I have not implemented range sharing or alias addressing.
-    
-======================================================================*/
-
-int pcmcia_request_io(client_handle_t handle, io_req_t *req)
-{
-    struct pcmcia_socket *s;
-    config_t *c;
-    
-    if (CHECK_HANDLE(handle))
-       return CS_BAD_HANDLE;
-    s = SOCKET(handle);
-    if (!(s->state & SOCKET_PRESENT))
-       return CS_NO_CARD;
-
-    if (handle->state & CLIENT_CARDBUS) {
-#ifdef CONFIG_CARDBUS
-       handle->state |= CLIENT_IO_REQ;
-       return CS_SUCCESS;
-#else
-       return CS_UNSUPPORTED_FUNCTION;
-#endif
-    }
-
-    if (!req)
-       return CS_UNSUPPORTED_MODE;
-    c = CONFIG(handle);
-    if (c->state & CONFIG_LOCKED)
-       return CS_CONFIGURATION_LOCKED;
-    if (c->state & CONFIG_IO_REQ)
-       return CS_IN_USE;
-    if (req->Attributes1 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS))
-       return CS_BAD_ATTRIBUTE;
-    if ((req->NumPorts2 > 0) &&
-       (req->Attributes2 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS)))
-       return CS_BAD_ATTRIBUTE;
-
-    if (alloc_io_space(s, req->Attributes1, &req->BasePort1,
-                      req->NumPorts1, req->IOAddrLines))
-       return CS_IN_USE;
-
-    if (req->NumPorts2) {
-       if (alloc_io_space(s, req->Attributes2, &req->BasePort2,
-                          req->NumPorts2, req->IOAddrLines)) {
-           release_io_space(s, req->BasePort1, req->NumPorts1);
-           return CS_IN_USE;
-       }
-    }
-
-    c->io = *req;
-    c->state |= CONFIG_IO_REQ;
-    handle->state |= CLIENT_IO_REQ;
-    return CS_SUCCESS;
-} /* request_io */
-
-/*======================================================================
-
-    Request_irq() reserves an irq for this client.
-
-    Also, since Linux only reserves irq's when they are actually
-    hooked, we don't guarantee that an irq will still be available
-    when the configuration is locked.  Now that I think about it,
-    there might be a way to fix this using a dummy handler.
-    
-======================================================================*/
-
-#ifdef CONFIG_PCMCIA_PROBE
-static irqreturn_t test_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
-       return IRQ_NONE;
-}
-#endif
-
-int pcmcia_request_irq(client_handle_t handle, irq_req_t *req)
-{
-       struct pcmcia_socket *s;
-       config_t *c;
-       int ret = CS_IN_USE, irq = 0;
-       struct pcmcia_device *p_dev = handle_to_pdev(handle);
-
-       if (CHECK_HANDLE(handle))
-               return CS_BAD_HANDLE;
-       s = SOCKET(handle);
-       if (!(s->state & SOCKET_PRESENT))
-               return CS_NO_CARD;
-       c = CONFIG(handle);
-       if (c->state & CONFIG_LOCKED)
-               return CS_CONFIGURATION_LOCKED;
-       if (c->state & CONFIG_IRQ_REQ)
-               return CS_IN_USE;
-
-#ifdef CONFIG_PCMCIA_PROBE
-       if (s->irq.AssignedIRQ != 0) {
-               /* If the interrupt is already assigned, it must be the same */
-               irq = s->irq.AssignedIRQ;
-       } else {
-               int try;
-               u32 mask = s->irq_mask;
-               void *data = NULL;
-
-               for (try = 0; try < 64; try++) {
-                       irq = try % 32;
-
-                       /* marked as available by driver, and not blocked by userspace? */
-                       if (!((mask >> irq) & 1))
-                               continue;
-
-                       /* avoid an IRQ which is already used by a PCMCIA card */
-                       if ((try < 32) && pcmcia_used_irq[irq])
-                               continue;
-
-                       /* register the correct driver, if possible, of check whether
-                        * registering a dummy handle works, i.e. if the IRQ isn't
-                        * marked as used by the kernel resource management core */
-                       ret = request_irq(irq,
-                                         (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Handler : test_action,
-                                         ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) ||
-                                          (s->functions > 1) ||
-                                          (irq == s->pci_irq)) ? SA_SHIRQ : 0,
-                                         p_dev->dev.bus_id,
-                                         (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Instance : data);
-                       if (!ret) {
-                               if (!(req->Attributes & IRQ_HANDLE_PRESENT))
-                                       free_irq(irq, data);
-                               break;
-                       }
-               }
-       }
-#endif
-       if (ret) {
-               if (!s->pci_irq)
-                       return ret;
-               irq = s->pci_irq;
-       }
-
-       if (ret && req->Attributes & IRQ_HANDLE_PRESENT) {
-               if (request_irq(irq, req->Handler,
-                               ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) ||
-                                (s->functions > 1) ||
-                                (irq == s->pci_irq)) ? SA_SHIRQ : 0,
-                               p_dev->dev.bus_id, req->Instance))
-                       return CS_IN_USE;
-       }
-
-       c->irq.Attributes = req->Attributes;
-       s->irq.AssignedIRQ = req->AssignedIRQ = irq;
-       s->irq.Config++;
-
-       c->state |= CONFIG_IRQ_REQ;
-       handle->state |= CLIENT_IRQ_REQ;
-
-#ifdef CONFIG_PCMCIA_PROBE
-       pcmcia_used_irq[irq]++;
-#endif
-
-       return CS_SUCCESS;
-} /* pcmcia_request_irq */
-
-/*======================================================================
-
-    Request_window() establishes a mapping between card memory space
-    and system memory space.
-
-======================================================================*/
-
-int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle_t *wh)
-{
-    struct pcmcia_socket *s;
-    window_t *win;
-    u_long align;
-    int w;
-    
-    if (CHECK_HANDLE(*handle))
-       return CS_BAD_HANDLE;
-    s = (*handle)->Socket;
-    if (!(s->state & SOCKET_PRESENT))
-       return CS_NO_CARD;
-    if (req->Attributes & (WIN_PAGED | WIN_SHARED))
-       return CS_BAD_ATTRIBUTE;
-
-    /* Window size defaults to smallest available */
-    if (req->Size == 0)
-       req->Size = s->map_size;
-    align = (((s->features & SS_CAP_MEM_ALIGN) ||
-             (req->Attributes & WIN_STRICT_ALIGN)) ?
-            req->Size : s->map_size);
-    if (req->Size & (s->map_size-1))
-       return CS_BAD_SIZE;
-    if ((req->Base && (s->features & SS_CAP_STATIC_MAP)) ||
-       (req->Base & (align-1)))
-       return CS_BAD_BASE;
-    if (req->Base)
-       align = 0;
-
-    /* Allocate system memory window */
-    for (w = 0; w < MAX_WIN; w++)
-       if (!(s->state & SOCKET_WIN_REQ(w))) break;
-    if (w == MAX_WIN)
-       return CS_OUT_OF_RESOURCE;
-
-    win = &s->win[w];
-    win->magic = WINDOW_MAGIC;
-    win->index = w;
-    win->handle = *handle;
-    win->sock = s;
-
-    if (!(s->features & SS_CAP_STATIC_MAP)) {
-       win->ctl.res = find_mem_region(req->Base, req->Size, align,
-                                      (req->Attributes & WIN_MAP_BELOW_1MB), s);
-       if (!win->ctl.res)
-           return CS_IN_USE;
-    }
-    (*handle)->state |= CLIENT_WIN_REQ(w);
-
-    /* Configure the socket controller */
-    win->ctl.map = w+1;
-    win->ctl.flags = 0;
-    win->ctl.speed = req->AccessSpeed;
-    if (req->Attributes & WIN_MEMORY_TYPE)
-       win->ctl.flags |= MAP_ATTRIB;
-    if (req->Attributes & WIN_ENABLE)
-       win->ctl.flags |= MAP_ACTIVE;
-    if (req->Attributes & WIN_DATA_WIDTH_16)
-       win->ctl.flags |= MAP_16BIT;
-    if (req->Attributes & WIN_USE_WAIT)
-       win->ctl.flags |= MAP_USE_WAIT;
-    win->ctl.card_start = 0;
-    if (s->ops->set_mem_map(s, &win->ctl) != 0)
-       return CS_BAD_ARGS;
-    s->state |= SOCKET_WIN_REQ(w);
-
-    /* Return window handle */
-    if (s->features & SS_CAP_STATIC_MAP) {
-       req->Base = win->ctl.static_start;
-    } else {
-       req->Base = win->ctl.res->start;
-    }
-    *wh = win;
-    
-    return CS_SUCCESS;
-} /* request_window */
-
-/*======================================================================
-
-    I'm not sure which "reset" function this is supposed to use,
-    but for now, it uses the low-level interface's reset, not the
-    CIS register.
-    
-======================================================================*/
+/* I'm not sure which "reset" function this is supposed to use,
+ * but for now, it uses the low-level interface's reset, not the
+ * CIS register.
+ */
 
 int pccard_reset_card(struct pcmcia_socket *skt)
 {
        int ret;
-    
+
        cs_dbg(skt, 1, "resetting socket\n");
 
        down(&skt->skt_sem);
@@ -1757,17 +778,14 @@ int pccard_reset_card(struct pcmcia_socket *skt)
 } /* reset_card */
 EXPORT_SYMBOL(pccard_reset_card);
 
-/*======================================================================
-
-    These shut down or wake up a socket.  They are sort of user
-    initiated versions of the APM suspend and resume actions.
-    
-======================================================================*/
 
+/* These shut down or wake up a socket.  They are sort of user
+ * initiated versions of the APM suspend and resume actions.
+ */
 int pcmcia_suspend_card(struct pcmcia_socket *skt)
 {
        int ret;
-    
+
        cs_dbg(skt, 1, "suspending socket\n");
 
        down(&skt->skt_sem);
@@ -1786,6 +804,8 @@ int pcmcia_suspend_card(struct pcmcia_socket *skt)
 
        return ret;
 } /* suspend_card */
+EXPORT_SYMBOL(pcmcia_suspend_card);
+
 
 int pcmcia_resume_card(struct pcmcia_socket *skt)
 {
@@ -1809,13 +829,10 @@ int pcmcia_resume_card(struct pcmcia_socket *skt)
 
        return ret;
 } /* resume_card */
+EXPORT_SYMBOL(pcmcia_resume_card);
 
-/*======================================================================
-
-    These handle user requests to eject or insert a card.
-    
-======================================================================*/
 
+/* These handle user requests to eject or insert a card. */
 int pcmcia_eject_card(struct pcmcia_socket *skt)
 {
        int ret;
@@ -1842,6 +859,8 @@ int pcmcia_eject_card(struct pcmcia_socket *skt)
 
        return ret;
 } /* eject_card */
+EXPORT_SYMBOL(pcmcia_eject_card);
+
 
 int pcmcia_insert_card(struct pcmcia_socket *skt)
 {
@@ -1865,37 +884,38 @@ int pcmcia_insert_card(struct pcmcia_socket *skt)
 
        return ret;
 } /* insert_card */
+EXPORT_SYMBOL(pcmcia_insert_card);
 
-/*======================================================================
 
-    OS-specific module glue goes here
-    
-======================================================================*/
-/* in alpha order */
-EXPORT_SYMBOL(pcmcia_eject_card);
-EXPORT_SYMBOL(pcmcia_get_card_services_info);
-EXPORT_SYMBOL(pcmcia_get_mem_page);
-EXPORT_SYMBOL(pcmcia_insert_card);
-EXPORT_SYMBOL(pcmcia_map_mem_page);
-EXPORT_SYMBOL(pcmcia_modify_configuration);
-EXPORT_SYMBOL(pcmcia_release_configuration);
-EXPORT_SYMBOL(pcmcia_release_io);
-EXPORT_SYMBOL(pcmcia_release_irq);
-EXPORT_SYMBOL(pcmcia_release_window);
-EXPORT_SYMBOL(pcmcia_replace_cis);
-EXPORT_SYMBOL(pcmcia_request_configuration);
-EXPORT_SYMBOL(pcmcia_request_io);
-EXPORT_SYMBOL(pcmcia_request_irq);
-EXPORT_SYMBOL(pcmcia_request_window);
-EXPORT_SYMBOL(pcmcia_resume_card);
-EXPORT_SYMBOL(pcmcia_suspend_card);
+static int pcmcia_socket_hotplug(struct class_device *dev, char **envp,
+                               int num_envp, char *buffer, int buffer_size)
+{
+       struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev);
+       int i = 0, length = 0;
+
+       if (add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size,
+                               &length, "SOCKET_NO=%u", s->sock))
+               return -ENOMEM;
+
+       envp[i] = NULL;
+
+       return 0;
+}
+
+
+static struct completion pcmcia_unload;
+
+static void pcmcia_release_socket_class(struct class *data)
+{
+       complete(&pcmcia_unload);
+}
 
-EXPORT_SYMBOL(dead_socket);
-EXPORT_SYMBOL(pcmcia_parse_events);
 
 struct class pcmcia_socket_class = {
        .name = "pcmcia_socket",
+        .hotplug = pcmcia_socket_hotplug,
        .release = pcmcia_release_socket,
+       .class_release = pcmcia_release_socket_class,
 };
 EXPORT_SYMBOL(pcmcia_socket_class);
 
@@ -1903,9 +923,8 @@ EXPORT_SYMBOL(pcmcia_socket_class);
 static int __init init_pcmcia_cs(void)
 {
        int ret;
-       printk(KERN_INFO "%s\n", release);
-       printk(KERN_INFO "  %s\n", options);
 
+       init_completion(&pcmcia_unload);
        ret = class_register(&pcmcia_socket_class);
        if (ret)
                return (ret);
@@ -1914,13 +933,12 @@ static int __init init_pcmcia_cs(void)
 
 static void __exit exit_pcmcia_cs(void)
 {
-    printk(KERN_INFO "unloading Kernel Card Services\n");
-    class_interface_unregister(&pccard_sysfs_interface);
-    class_unregister(&pcmcia_socket_class);
+       class_interface_unregister(&pccard_sysfs_interface);
+       class_unregister(&pcmcia_socket_class);
+
+       wait_for_completion(&pcmcia_unload);
 }
 
 subsys_initcall(init_pcmcia_cs);
 module_exit(exit_pcmcia_cs);
 
-/*====================================================================*/
-
index 7933a7d..0b4c18e 100644 (file)
@@ -123,9 +123,9 @@ void cb_free(struct pcmcia_socket *s);
 int read_cb_mem(struct pcmcia_socket *s, int space, u_int addr, u_int len, void *ptr);
 
 /* In cistpl.c */
-int read_cis_mem(struct pcmcia_socket *s, int attr,
+int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr,
                 u_int addr, u_int len, void *ptr);
-void write_cis_mem(struct pcmcia_socket *s, int attr,
+void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr,
                   u_int addr, u_int len, void *ptr);
 void release_cis_mem(struct pcmcia_socket *s);
 void destroy_cis_cache(struct pcmcia_socket *s);
@@ -134,13 +134,12 @@ int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function, cisdata_t
 
 /* In rsrc_mgr */
 void pcmcia_validate_mem(struct pcmcia_socket *s);
-struct resource *find_io_region(unsigned long base, int num, unsigned long align,
+struct resource *pcmcia_find_io_region(unsigned long base, int num, unsigned long align,
                   struct pcmcia_socket *s);
-int adjust_io_region(struct resource *res, unsigned long r_start,
+int pcmcia_adjust_io_region(struct resource *res, unsigned long r_start,
                     unsigned long r_end, struct pcmcia_socket *s);
-struct resource *find_mem_region(u_long base, u_long num, u_long align,
+struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align,
                    int low, struct pcmcia_socket *s);
-int adjust_resource_info(client_handle_t handle, adjust_t *adj);
 void release_resource_db(struct pcmcia_socket *s);
 
 /* In socket_sysfs.c */
@@ -159,7 +158,7 @@ int pccard_access_configuration_register(struct pcmcia_socket *s, unsigned int f
 struct pcmcia_callback{
        struct module   *owner;
        int             (*event) (struct pcmcia_socket *s, event_t event, int priority);
-       int             (*resources_done) (struct pcmcia_socket *s);
+       void            (*requery) (struct pcmcia_socket *s);
 };
 
 int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c);
index 569e55f..cabddd4 100644 (file)
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * (C) 1999            David A. Hinds
- * (C) 2003 - 2004     Dominik Brodowski
+ * (C) 2003 - 2005     Dominik Brodowski
  */
 
 #include <linux/config.h>
+#include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/string.h>
 #include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/timer.h>
-#include <linux/ioctl.h>
-#include <linux/proc_fs.h>
-#include <linux/poll.h>
-#include <linux/pci.h>
 #include <linux/list.h>
 #include <linux/delay.h>
-#include <linux/kref.h>
 #include <linux/workqueue.h>
-
-#include <asm/atomic.h>
+#include <linux/crc32.h>
+#include <linux/firmware.h>
 
 #define IN_CARD_SERVICES
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
-#include <pcmcia/bulkmem.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 #include <pcmcia/ss.h>
 
 #include "cs_internal.h"
+#include "ds_internal.h"
 
 /*====================================================================*/
 
@@ -70,49 +55,9 @@ module_param_named(pc_debug, ds_pc_debug, int, 0644);
 #define ds_dbg(lvl, fmt, arg...) do { } while (0)
 #endif
 
-/*====================================================================*/
+spinlock_t pcmcia_dev_list_lock;
 
-/* Device user information */
-#define MAX_EVENTS     32
-#define USER_MAGIC     0x7ea4
-#define CHECK_USER(u) \
-    (((u) == NULL) || ((u)->user_magic != USER_MAGIC))
-typedef struct user_info_t {
-    u_int              user_magic;
-    int                        event_head, event_tail;
-    event_t            event[MAX_EVENTS];
-    struct user_info_t *next;
-    struct pcmcia_bus_socket *socket;
-} user_info_t;
-
-/* Socket state information */
-struct pcmcia_bus_socket {
-       struct kref             refcount;
-       struct pcmcia_callback  callback;
-       int                     state;
-       user_info_t             *user;
-       wait_queue_head_t       queue;
-       struct pcmcia_socket    *parent;
-
-       /* the PCMCIA devices connected to this socket (normally one, more
-        * for multifunction devices: */
-       struct list_head        devices_list;
-       u8                      device_count; /* the number of devices, used
-                                              * only internally and subject
-                                              * to incorrectness and change */
-};
-static spinlock_t pcmcia_dev_list_lock;
-
-#define DS_SOCKET_PRESENT              0x01
-#define DS_SOCKET_BUSY                 0x02
-#define DS_SOCKET_REMOVAL_PENDING      0x10
-#define DS_SOCKET_DEAD                 0x80
-
-/*====================================================================*/
-
-static int major_dev = -1;
-
-static int unbind_request(struct pcmcia_bus_socket *s);
+static int unbind_request(struct pcmcia_socket *s);
 
 /*====================================================================*/
 
@@ -213,7 +158,7 @@ static const lookup_t service_table[] = {
 };
 
 
-int pcmcia_report_error(client_handle_t handle, error_info_t *err)
+static int pcmcia_report_error(client_handle_t handle, error_info_t *err)
 {
        int i;
        char *serv;
@@ -243,7 +188,6 @@ int pcmcia_report_error(client_handle_t handle, error_info_t *err)
 
        return CS_SUCCESS;
 } /* report_error */
-EXPORT_SYMBOL(pcmcia_report_error);
 
 /* end of code which was in cs.c before */
 
@@ -256,29 +200,101 @@ void cs_error(client_handle_t handle, int func, int ret)
 }
 EXPORT_SYMBOL(cs_error);
 
-/*======================================================================*/
-
-static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info);
-static struct pcmcia_bus_socket * get_socket_info_by_nr(unsigned int nr);
 
-static void pcmcia_release_bus_socket(struct kref *refcount)
+static void pcmcia_check_driver(struct pcmcia_driver *p_drv)
 {
-       struct pcmcia_bus_socket *s = container_of(refcount, struct pcmcia_bus_socket, refcount);
-       pcmcia_put_socket(s->parent);
-       kfree(s);
+       struct pcmcia_device_id *did = p_drv->id_table;
+       unsigned int i;
+       u32 hash;
+
+       while (did && did->match_flags) {
+               for (i=0; i<4; i++) {
+                       if (!did->prod_id[i])
+                               continue;
+
+                       hash = crc32(0, did->prod_id[i], strlen(did->prod_id[i]));
+                       if (hash == did->prod_id_hash[i])
+                               continue;
+
+                       printk(KERN_DEBUG "pcmcia: %s: invalid hash for "
+                              "product string \"%s\": is 0x%x, should "
+                              "be 0x%x\n", p_drv->drv.name, did->prod_id[i],
+                              did->prod_id_hash[i], hash);
+                       printk(KERN_DEBUG "pcmcia: see "
+                               "Documentation/pcmcia/devicetable.txt for "
+                               "details\n");
+               }
+               did++;
+       }
+
+       return;
 }
 
-static void pcmcia_put_bus_socket(struct pcmcia_bus_socket *s)
+
+#ifdef CONFIG_PCMCIA_LOAD_CIS
+
+/**
+ * pcmcia_load_firmware - load CIS from userspace if device-provided is broken
+ * @dev - the pcmcia device which needs a CIS override
+ * @filename - requested filename in /lib/firmware/cis/
+ *
+ * This uses the in-kernel firmware loading mechanism to use a "fake CIS" if
+ * the one provided by the card is broken. The firmware files reside in
+ * /lib/firmware/cis/ in userspace.
+ */
+static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
 {
-       kref_put(&s->refcount, pcmcia_release_bus_socket);
+       struct pcmcia_socket *s = dev->socket;
+       const struct firmware *fw;
+       char path[20];
+       int ret=-ENOMEM;
+       cisdump_t *cis;
+
+       if (!filename)
+               return -EINVAL;
+
+       ds_dbg(1, "trying to load firmware %s\n", filename);
+
+       if (strlen(filename) > 14)
+               return -EINVAL;
+
+       snprintf(path, 20, "%s", filename);
+
+       if (request_firmware(&fw, path, &dev->dev) == 0) {
+               if (fw->size >= CISTPL_MAX_CIS_SIZE)
+                       goto release;
+
+               cis = kmalloc(sizeof(cisdump_t), GFP_KERNEL);
+               if (!cis)
+                       goto release;
+
+               memset(cis, 0, sizeof(cisdump_t));
+
+               cis->Length = fw->size + 1;
+               memcpy(cis->Data, fw->data, fw->size);
+
+               if (!pcmcia_replace_cis(s, cis))
+                       ret = 0;
+       }
+ release:
+       release_firmware(fw);
+
+       return (ret);
 }
 
-static struct pcmcia_bus_socket *pcmcia_get_bus_socket(struct pcmcia_bus_socket *s)
+#else /* !CONFIG_PCMCIA_LOAD_CIS */
+
+static inline int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
 {
-       kref_get(&s->refcount);
-       return (s);
+       return -ENODEV;
 }
 
+#endif
+
+
+/*======================================================================*/
+
+
 /**
  * pcmcia_register_driver - register a PCMCIA driver with the bus core
  *
@@ -292,6 +308,8 @@ int pcmcia_register_driver(struct pcmcia_driver *driver)
        if (!driver)
                return -EINVAL;
 
+       pcmcia_check_driver(driver);
+
        /* initialize common fields */
        driver->drv.bus = &pcmcia_bus_type;
        driver->drv.owner = driver->owner;
@@ -311,42 +329,10 @@ void pcmcia_unregister_driver(struct pcmcia_driver *driver)
 }
 EXPORT_SYMBOL(pcmcia_unregister_driver);
 
-#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry *proc_pccard = NULL;
-
-static int proc_read_drivers_callback(struct device_driver *driver, void *d)
-{
-       char **p = d;
-       struct pcmcia_driver *p_drv = container_of(driver,
-                                                  struct pcmcia_driver, drv);
-
-       *p += sprintf(*p, "%-24.24s 1 %d\n", p_drv->drv.name,
-#ifdef CONFIG_MODULE_UNLOAD
-                     (p_drv->owner) ? module_refcount(p_drv->owner) : 1
-#else
-                     1
-#endif
-       );
-       d = (void *) p;
-
-       return 0;
-}
-
-static int proc_read_drivers(char *buf, char **start, off_t pos,
-                            int count, int *eof, void *data)
-{
-       char *p = buf;
-
-       bus_for_each_drv(&pcmcia_bus_type, NULL, 
-                        (void *) &p, proc_read_drivers_callback);
-
-       return (p - buf);
-}
-#endif
 
 /* pcmcia_device handling */
 
-static struct pcmcia_device * pcmcia_get_dev(struct pcmcia_device *p_dev)
+struct pcmcia_device * pcmcia_get_dev(struct pcmcia_device *p_dev)
 {
        struct device *tmp_dev;
        tmp_dev = get_device(&p_dev->dev);
@@ -355,7 +341,7 @@ static struct pcmcia_device * pcmcia_get_dev(struct pcmcia_device *p_dev)
        return to_pcmcia_dev(tmp_dev);
 }
 
-static void pcmcia_put_dev(struct pcmcia_device *p_dev)
+void pcmcia_put_dev(struct pcmcia_device *p_dev)
 {
        if (p_dev)
                put_device(&p_dev->dev);
@@ -365,7 +351,7 @@ static void pcmcia_release_dev(struct device *dev)
 {
        struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
        ds_dbg(1, "releasing dev %p\n", p_dev);
-       pcmcia_put_bus_socket(p_dev->socket->pcmcia);
+       pcmcia_put_socket(p_dev->socket);
        kfree(p_dev);
 }
 
@@ -500,34 +486,38 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev)
  */
 static DECLARE_MUTEX(device_add_lock);
 
-static struct pcmcia_device * pcmcia_device_add(struct pcmcia_bus_socket *s, unsigned int function)
+struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int function)
 {
        struct pcmcia_device *p_dev;
        unsigned long flags;
 
-       s = pcmcia_get_bus_socket(s);
+       s = pcmcia_get_socket(s);
        if (!s)
                return NULL;
 
        down(&device_add_lock);
 
+       /* max of 2 devices per card */
+       if (s->device_count == 2)
+               goto err_put;
+
        p_dev = kmalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
        if (!p_dev)
                goto err_put;
        memset(p_dev, 0, sizeof(struct pcmcia_device));
 
-       p_dev->socket = s->parent;
+       p_dev->socket = s;
        p_dev->device_no = (s->device_count++);
        p_dev->func   = function;
 
        p_dev->dev.bus = &pcmcia_bus_type;
-       p_dev->dev.parent = s->parent->dev.dev;
+       p_dev->dev.parent = s->dev.dev;
        p_dev->dev.release = pcmcia_release_dev;
        sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no);
 
        /* compat */
        p_dev->client.client_magic = CLIENT_MAGIC;
-       p_dev->client.Socket = s->parent;
+       p_dev->client.Socket = s;
        p_dev->client.Function = function;
        p_dev->client.state = CLIENT_UNBOUND;
 
@@ -536,6 +526,8 @@ static struct pcmcia_device * pcmcia_device_add(struct pcmcia_bus_socket *s, uns
        list_add_tail(&p_dev->socket_device_list, &s->devices_list);
        spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
 
+       pcmcia_device_query(p_dev);
+
        if (device_register(&p_dev->dev)) {
                spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
                list_del(&p_dev->socket_device_list);
@@ -553,7 +545,7 @@ static struct pcmcia_device * pcmcia_device_add(struct pcmcia_bus_socket *s, uns
        s->device_count--;
  err_put:
        up(&device_add_lock);
-       pcmcia_put_bus_socket(s);
+       pcmcia_put_socket(s);
 
        return NULL;
 }
@@ -584,23 +576,252 @@ static int pcmcia_card_add(struct pcmcia_socket *s)
        /* this doesn't handle multifunction devices on one pcmcia function
         * yet. */
        for (i=0; i < no_funcs; i++)
-               pcmcia_device_add(s->pcmcia, i);
+               pcmcia_device_add(s, i);
 
        return (ret);
 }
 
 
+static void pcmcia_delayed_add_pseudo_device(void *data)
+{
+       struct pcmcia_socket *s = data;
+       pcmcia_device_add(s, 0);
+       s->pcmcia_state.device_add_pending = 0;
+}
+
+static inline void pcmcia_add_pseudo_device(struct pcmcia_socket *s)
+{
+       if (!s->pcmcia_state.device_add_pending) {
+               schedule_work(&s->device_add);
+               s->pcmcia_state.device_add_pending = 1;
+       }
+       return;
+}
+
+static int pcmcia_requery(struct device *dev, void * _data)
+{
+       struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+       if (!p_dev->dev.driver)
+               pcmcia_device_query(p_dev);
+
+       return 0;
+}
+
+static void pcmcia_bus_rescan(struct pcmcia_socket *skt)
+{
+       int no_devices=0;
+       unsigned long flags;
+
+       /* must be called with skt_sem held */
+       spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+       if (list_empty(&skt->devices_list))
+               no_devices=1;
+       spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+
+       /* if no devices were added for this socket yet because of
+        * missing resource information or other trouble, we need to
+        * do this now. */
+       if (no_devices) {
+               int ret = pcmcia_card_add(skt);
+               if (ret)
+                       return;
+       }
+
+       /* some device information might have changed because of a CIS
+        * update or because we can finally read it correctly... so
+        * determine it again, overwriting old values if necessary. */
+       bus_for_each_dev(&pcmcia_bus_type, NULL, NULL, pcmcia_requery);
+
+       /* we re-scan all devices, not just the ones connected to this
+        * socket. This does not matter, though. */
+       bus_rescan_devices(&pcmcia_bus_type);
+}
+
+static inline int pcmcia_devmatch(struct pcmcia_device *dev,
+                                 struct pcmcia_device_id *did)
+{
+       if (did->match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID) {
+               if ((!dev->has_manf_id) || (dev->manf_id != did->manf_id))
+                       return 0;
+       }
+
+       if (did->match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID) {
+               if ((!dev->has_card_id) || (dev->card_id != did->card_id))
+                       return 0;
+       }
+
+       if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNCTION) {
+               if (dev->func != did->function)
+                       return 0;
+       }
+
+       if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1) {
+               if (!dev->prod_id[0])
+                       return 0;
+               if (strcmp(did->prod_id[0], dev->prod_id[0]))
+                       return 0;
+       }
+
+       if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2) {
+               if (!dev->prod_id[1])
+                       return 0;
+               if (strcmp(did->prod_id[1], dev->prod_id[1]))
+                       return 0;
+       }
+
+       if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3) {
+               if (!dev->prod_id[2])
+                       return 0;
+               if (strcmp(did->prod_id[2], dev->prod_id[2]))
+                       return 0;
+       }
+
+       if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4) {
+               if (!dev->prod_id[3])
+                       return 0;
+               if (strcmp(did->prod_id[3], dev->prod_id[3]))
+                       return 0;
+       }
+
+       if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) {
+               /* handle pseudo multifunction devices:
+                * there are at most two pseudo multifunction devices.
+                * if we're matching against the first, schedule a
+                * call which will then check whether there are two
+                * pseudo devices, and if not, add the second one.
+                */
+               if (dev->device_no == 0)
+                       pcmcia_add_pseudo_device(dev->socket);
+
+               if (dev->device_no != did->device_no)
+                       return 0;
+       }
+
+       if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID) {
+               if ((!dev->has_func_id) || (dev->func_id != did->func_id))
+                       return 0;
+
+               /* if this is a pseudo-multi-function device,
+                * we need explicit matches */
+               if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO)
+                       return 0;
+               if (dev->device_no)
+                       return 0;
+
+               /* also, FUNC_ID matching needs to be activated by userspace
+                * after it has re-checked that there is no possible module
+                * with a prod_id/manf_id/card_id match.
+                */
+               if (!dev->allow_func_id_match)
+                       return 0;
+       }
+
+       if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) {
+               if (!dev->socket->fake_cis)
+                       pcmcia_load_firmware(dev, did->cisfile);
+
+               if (!dev->socket->fake_cis)
+                       return 0;
+       }
+
+       if (did->match_flags & PCMCIA_DEV_ID_MATCH_ANONYMOUS) {
+               int i;
+               for (i=0; i<4; i++)
+                       if (dev->prod_id[i])
+                               return 0;
+               if (dev->has_manf_id || dev->has_card_id || dev->has_func_id)
+                       return 0;
+       }
+
+       dev->dev.driver_data = (void *) did;
+
+       return 1;
+}
+
+
 static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) {
        struct pcmcia_device * p_dev = to_pcmcia_dev(dev);
        struct pcmcia_driver * p_drv = to_pcmcia_drv(drv);
+       struct pcmcia_device_id *did = p_drv->id_table;
 
        /* matching by cardmgr */
        if (p_dev->cardmgr == p_drv)
                return 1;
 
+       while (did && did->match_flags) {
+               if (pcmcia_devmatch(p_dev, did))
+                       return 1;
+               did++;
+       }
+
        return 0;
 }
 
+#ifdef CONFIG_HOTPLUG
+
+static int pcmcia_bus_hotplug(struct device *dev, char **envp, int num_envp,
+                             char *buffer, int buffer_size)
+{
+       struct pcmcia_device *p_dev;
+       int i, length = 0;
+       u32 hash[4] = { 0, 0, 0, 0};
+
+       if (!dev)
+               return -ENODEV;
+
+       p_dev = to_pcmcia_dev(dev);
+
+       /* calculate hashes */
+       for (i=0; i<4; i++) {
+               if (!p_dev->prod_id[i])
+                       continue;
+               hash[i] = crc32(0, p_dev->prod_id[i], strlen(p_dev->prod_id[i]));
+       }
+
+       i = 0;
+
+       if (add_hotplug_env_var(envp, num_envp, &i,
+                               buffer, buffer_size, &length,
+                               "SOCKET_NO=%u",
+                               p_dev->socket->sock))
+               return -ENOMEM;
+
+       if (add_hotplug_env_var(envp, num_envp, &i,
+                               buffer, buffer_size, &length,
+                               "DEVICE_NO=%02X",
+                               p_dev->device_no))
+               return -ENOMEM;
+
+       if (add_hotplug_env_var(envp, num_envp, &i,
+                               buffer, buffer_size, &length,
+                               "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
+                               "pa%08Xpb%08Xpc%08Xpd%08X",
+                               p_dev->has_manf_id ? p_dev->manf_id : 0,
+                               p_dev->has_card_id ? p_dev->card_id : 0,
+                               p_dev->has_func_id ? p_dev->func_id : 0,
+                               p_dev->func,
+                               p_dev->device_no,
+                               hash[0],
+                               hash[1],
+                               hash[2],
+                               hash[3]))
+               return -ENOMEM;
+
+       envp[i] = NULL;
+
+       return 0;
+}
+
+#else
+
+static int pcmcia_bus_hotplug(struct device *dev, char **envp, int num_envp,
+                             char *buffer, int buffer_size)
+{
+       return -ENODEV;
+}
+
+#endif
+
 /************************ per-device sysfs output ***************************/
 
 #define pcmcia_device_attr(field, test, format)                                \
@@ -626,6 +847,43 @@ pcmcia_device_stringattr(prod_id2, prod_id[1]);
 pcmcia_device_stringattr(prod_id3, prod_id[2]);
 pcmcia_device_stringattr(prod_id4, prod_id[3]);
 
+static ssize_t modalias_show(struct device *dev, char *buf)
+{
+       struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+       int i;
+       u32 hash[4] = { 0, 0, 0, 0};
+
+       /* calculate hashes */
+       for (i=0; i<4; i++) {
+               if (!p_dev->prod_id[i])
+                       continue;
+               hash[i] = crc32(0,p_dev->prod_id[i],strlen(p_dev->prod_id[i]));
+       }
+       return sprintf(buf, "pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
+                               "pa%08Xpb%08Xpc%08Xpd%08X\n",
+                               p_dev->has_manf_id ? p_dev->manf_id : 0,
+                               p_dev->has_card_id ? p_dev->card_id : 0,
+                               p_dev->has_func_id ? p_dev->func_id : 0,
+                               p_dev->func, p_dev->device_no,
+                               hash[0], hash[1], hash[2], hash[3]);
+}
+
+static ssize_t pcmcia_store_allow_func_id_match(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+        if (!count)
+                return -EINVAL;
+
+       down(&p_dev->socket->skt_sem);
+       p_dev->allow_func_id_match = 1;
+       up(&p_dev->socket->skt_sem);
+
+       bus_rescan_devices(&pcmcia_bus_type);
+
+       return count;
+}
+
 static struct device_attribute pcmcia_dev_attrs[] = {
        __ATTR(function, 0444, func_show, NULL),
        __ATTR_RO(func_id),
@@ -635,44 +893,12 @@ static struct device_attribute pcmcia_dev_attrs[] = {
        __ATTR_RO(prod_id2),
        __ATTR_RO(prod_id3),
        __ATTR_RO(prod_id4),
+       __ATTR_RO(modalias),
+       __ATTR(allow_func_id_match, 0200, NULL, pcmcia_store_allow_func_id_match),
        __ATTR_NULL,
 };
 
 
-/*======================================================================
-
-    These manage a ring buffer of events pending for one user process
-    
-======================================================================*/
-
-static int queue_empty(user_info_t *user)
-{
-    return (user->event_head == user->event_tail);
-}
-
-static event_t get_queued_event(user_info_t *user)
-{
-    user->event_tail = (user->event_tail+1) % MAX_EVENTS;
-    return user->event[user->event_tail];
-}
-
-static void queue_event(user_info_t *user, event_t event)
-{
-    user->event_head = (user->event_head+1) % MAX_EVENTS;
-    if (user->event_head == user->event_tail)
-       user->event_tail = (user->event_tail+1) % MAX_EVENTS;
-    user->event[user->event_head] = event;
-}
-
-static void handle_event(struct pcmcia_bus_socket *s, event_t event)
-{
-    user_info_t *user;
-    for (user = s->user; user; user = user->next)
-       queue_event(user, event);
-    wake_up_interruptible(&s->queue);
-}
-
-
 /*======================================================================
 
     The card status event handler.
@@ -706,21 +932,13 @@ static int send_event_callback(struct device *dev, void * _data)
 
 static int send_event(struct pcmcia_socket *s, event_t event, int priority)
 {
-       int ret = 0;
        struct send_event_data private;
-       struct pcmcia_bus_socket *skt = pcmcia_get_bus_socket(s->pcmcia);
-
-       if (!skt)
-               return 0;
 
        private.skt = s;
        private.event = event;
        private.priority = priority;
 
-       ret = bus_for_each_dev(&pcmcia_bus_type, NULL, &private, send_event_callback);
-
-       pcmcia_put_bus_socket(skt);
-       return ret;
+       return bus_for_each_dev(&pcmcia_bus_type, NULL, &private, send_event_callback);
 } /* send_event */
 
 
@@ -731,25 +949,25 @@ static int send_event(struct pcmcia_socket *s, event_t event, int priority)
 
 static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
 {
-       struct pcmcia_bus_socket *s = skt->pcmcia;
+       struct pcmcia_socket *s = pcmcia_get_socket(skt);
        int ret = 0;
 
        ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n",
-              event, priority, s);
+              event, priority, skt);
     
        switch (event) {
 
        case CS_EVENT_CARD_REMOVAL:
-               s->state &= ~DS_SOCKET_PRESENT;
+               s->pcmcia_state.present = 0;
                send_event(skt, event, priority);
-               unbind_request(s);
-               handle_event(s, event);
+               unbind_request(skt);
+               handle_event(skt, event);
                break;
        
        case CS_EVENT_CARD_INSERTION:
-               s->state |= DS_SOCKET_PRESENT;
+               s->pcmcia_state.present = 1;
                pcmcia_card_add(skt);
-               handle_event(s, event);
+               handle_event(skt, event);
                break;
 
        case CS_EVENT_EJECTION_REQUEST:
@@ -757,137 +975,22 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
                break;
 
        default:
-               handle_event(s, event);
+               handle_event(skt, event);
                send_event(skt, event, priority);
                break;
     }
 
+    pcmcia_put_socket(s);
+
     return 0;
 } /* ds_event */
 
 
-/*======================================================================
-
-    bind_request() and bind_device() are merged by now. Register_client()
-    is called right at the end of bind_request(), during the driver's
-    ->attach() call. Individual descriptions:
-
-    bind_request() connects a socket to a particular client driver.
-    It looks up the specified device ID in the list of registered
-    drivers, binds it to the socket, and tries to create an instance
-    of the device.  unbind_request() deletes a driver instance.
-    
-    Bind_device() associates a device driver with a particular socket.
-    It is normally called by Driver Services after it has identified
-    a newly inserted card.  An instance of that driver will then be
-    eligible to register as a client of this socket.
-
-    Register_client() uses the dev_info_t handle to match the
-    caller with a socket.  The driver must have already been bound
-    to a socket with bind_device() -- in fact, bind_device()
-    allocates the client structure that will be used.
-
-======================================================================*/
-
-static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info)
-{
-       struct pcmcia_driver *p_drv;
-       struct pcmcia_device *p_dev;
-       int ret = 0;
-       unsigned long flags;
-
-       s = pcmcia_get_bus_socket(s);
-       if (!s)
-               return -EINVAL;
-
-       ds_dbg(2, "bind_request(%d, '%s')\n", s->parent->sock,
-              (char *)bind_info->dev_info);
-
-       p_drv = get_pcmcia_driver(&bind_info->dev_info);
-       if (!p_drv) {
-               ret = -EINVAL;
-               goto err_put;
-       }
-
-       if (!try_module_get(p_drv->owner)) {
-               ret = -EINVAL;
-               goto err_put_driver;
-       }
-
-       spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
-        list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
-               if (p_dev->func == bind_info->function) {
-                       if ((p_dev->dev.driver == &p_drv->drv)) {
-                               if (p_dev->cardmgr) {
-                                       /* if there's already a device
-                                        * registered, and it was registered
-                                        * by userspace before, we need to
-                                        * return the "instance". */
-                                       spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
-                                       bind_info->instance = p_dev->instance;
-                                       ret = -EBUSY;
-                                       goto err_put_module;
-                               } else {
-                                       /* the correct driver managed to bind
-                                        * itself magically to the correct
-                                        * device. */
-                                       spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
-                                       p_dev->cardmgr = p_drv;
-                                       ret = 0;
-                                       goto err_put_module;
-                               }
-                       } else if (!p_dev->dev.driver) {
-                               /* there's already a device available where
-                                * no device has been bound to yet. So we don't
-                                * need to register a device! */
-                               spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
-                               goto rescan;
-                       }
-               }
-       }
-       spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
-
-       p_dev = pcmcia_device_add(s, bind_info->function);
-       if (!p_dev) {
-               ret = -EIO;
-               goto err_put_module;
-       }
-
-rescan:
-       p_dev->cardmgr = p_drv;
-
-       pcmcia_device_query(p_dev);
-
-       /*
-        * Prevent this racing with a card insertion.
-        */
-       down(&s->parent->skt_sem);
-       bus_rescan_devices(&pcmcia_bus_type);
-       up(&s->parent->skt_sem);
-
-       /* check whether the driver indeed matched. I don't care if this
-        * is racy or not, because it can only happen on cardmgr access
-        * paths...
-        */
-       if (!(p_dev->dev.driver == &p_drv->drv))
-               p_dev->cardmgr = NULL;
-
- err_put_module:
-       module_put(p_drv->owner);
- err_put_driver:
-       put_driver(&p_drv->drv);
- err_put:
-       pcmcia_put_bus_socket(s);
-
-       return (ret);
-} /* bind_request */
-
 
 int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
 {
        client_t *client = NULL;
-       struct pcmcia_socket *s;
-       struct pcmcia_bus_socket *skt = NULL;
+       struct pcmcia_socket *s = NULL;
        struct pcmcia_device *p_dev = NULL;
 
        /* Look for unbound client with matching dev_info */
@@ -898,14 +1001,11 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
                if (s->state & SOCKET_CARDBUS)
                        continue;
 
-               skt = s->pcmcia;
-               if (!skt)
-                       continue;
-               skt = pcmcia_get_bus_socket(skt);
-               if (!skt)
+               s = pcmcia_get_socket(s);
+               if (!s)
                        continue;
                spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
-               list_for_each_entry(p_dev, &skt->devices_list, socket_device_list) {
+               list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
                        struct pcmcia_driver *p_drv;
                        p_dev = pcmcia_get_dev(p_dev);
                        if (!p_dev)
@@ -924,14 +1024,14 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
                        pcmcia_put_dev(p_dev);
                }
                spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
-               pcmcia_put_bus_socket(skt);
+               pcmcia_put_socket(s);
        }
  found:
        up_read(&pcmcia_socket_list_rwsem);
        if (!p_dev || !client)
                return -ENODEV;
 
-       pcmcia_put_bus_socket(skt); /* safe, as we already hold a reference from bind_device */
+       pcmcia_put_socket(s); /* safe, as we already hold a reference from bind_device */
 
        *handle = client;
        client->state &= ~CLIENT_UNBOUND;
@@ -978,106 +1078,15 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
 EXPORT_SYMBOL(pcmcia_register_client);
 
 
-/*====================================================================*/
-
-extern struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s);
-
-static int get_device_info(struct pcmcia_bus_socket *s, bind_info_t *bind_info, int first)
-{
-       dev_node_t *node;
-       struct pcmcia_device *p_dev;
-       unsigned long flags;
-       int ret = 0;
-
-#ifdef CONFIG_CARDBUS
-       /*
-        * Some unbelievably ugly code to associate the PCI cardbus
-        * device and its driver with the PCMCIA "bind" information.
-        */
-       {
-               struct pci_bus *bus;
-
-               bus = pcmcia_lookup_bus(s->parent);
-               if (bus) {
-                       struct list_head *list;
-                       struct pci_dev *dev = NULL;
-
-                       list = bus->devices.next;
-                       while (list != &bus->devices) {
-                               struct pci_dev *pdev = pci_dev_b(list);
-                               list = list->next;
-
-                               if (first) {
-                                       dev = pdev;
-                                       break;
-                               }
-
-                               /* Try to handle "next" here some way? */
-                       }
-                       if (dev && dev->driver) {
-                               strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN);
-                               bind_info->major = 0;
-                               bind_info->minor = 0;
-                               bind_info->next = NULL;
-                               return 0;
-                       }
-               }
-       }
-#endif
-
-       spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
-       list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
-               if (p_dev->func == bind_info->function) {
-                       p_dev = pcmcia_get_dev(p_dev);
-                       if (!p_dev)
-                               continue;
-                       goto found;
-               }
-       }
-       spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
-       return -ENODEV;
-
- found:
-       spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
-
-       if ((!p_dev->instance) ||
-           (p_dev->instance->state & DEV_CONFIG_PENDING)) {
-               ret = -EAGAIN;
-               goto err_put;
-       }
-
-       if (first)
-               node = p_dev->instance->dev;
-       else
-               for (node = p_dev->instance->dev; node; node = node->next)
-                       if (node == bind_info->next)
-                               break;
-       if (!node) {
-               ret = -ENODEV;
-               goto err_put;
-       }
-
-       strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
-       bind_info->major = node->major;
-       bind_info->minor = node->minor;
-       bind_info->next = node->next;
-
- err_put:
-       pcmcia_put_dev(p_dev);
-       return (ret);
-} /* get_device_info */
-
-/*====================================================================*/
-
 /* unbind _all_ devices attached to a given pcmcia_bus_socket. The
  * drivers have been called with EVENT_CARD_REMOVAL before.
  */
-static int unbind_request(struct pcmcia_bus_socket *s)
+static int unbind_request(struct pcmcia_socket *s)
 {
        struct pcmcia_device    *p_dev;
        unsigned long           flags;
 
-       ds_dbg(2, "unbind_request(%d)\n", s->parent->sock);
+       ds_dbg(2, "unbind_request(%d)\n", s->sock);
 
        s->device_count = 0;
 
@@ -1133,433 +1142,58 @@ int pcmcia_deregister_client(client_handle_t handle)
 } /* deregister_client */
 EXPORT_SYMBOL(pcmcia_deregister_client);
 
-
-/*======================================================================
-
-    The user-mode PC Card device interface
-
-======================================================================*/
-
-static int ds_open(struct inode *inode, struct file *file)
-{
-    socket_t i = iminor(inode);
-    struct pcmcia_bus_socket *s;
-    user_info_t *user;
-
-    ds_dbg(0, "ds_open(socket %d)\n", i);
-
-    s = get_socket_info_by_nr(i);
-    if (!s)
-           return -ENODEV;
-    s = pcmcia_get_bus_socket(s);
-    if (!s)
-           return -ENODEV;
-
-    if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
-           if (s->state & DS_SOCKET_BUSY) {
-                   pcmcia_put_bus_socket(s);
-                   return -EBUSY;
-           }
-       else
-           s->state |= DS_SOCKET_BUSY;
-    }
-    
-    user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
-    if (!user) {
-           pcmcia_put_bus_socket(s);
-           return -ENOMEM;
-    }
-    user->event_tail = user->event_head = 0;
-    user->next = s->user;
-    user->user_magic = USER_MAGIC;
-    user->socket = s;
-    s->user = user;
-    file->private_data = user;
-    
-    if (s->state & DS_SOCKET_PRESENT)
-       queue_event(user, CS_EVENT_CARD_INSERTION);
-    return 0;
-} /* ds_open */
-
-/*====================================================================*/
-
-static int ds_release(struct inode *inode, struct file *file)
-{
-    struct pcmcia_bus_socket *s;
-    user_info_t *user, **link;
-
-    ds_dbg(0, "ds_release(socket %d)\n", iminor(inode));
-
-    user = file->private_data;
-    if (CHECK_USER(user))
-       goto out;
-
-    s = user->socket;
-
-    /* Unlink user data structure */
-    if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
-       s->state &= ~DS_SOCKET_BUSY;
-    }
-    file->private_data = NULL;
-    for (link = &s->user; *link; link = &(*link)->next)
-       if (*link == user) break;
-    if (link == NULL)
-       goto out;
-    *link = user->next;
-    user->user_magic = 0;
-    kfree(user);
-    pcmcia_put_bus_socket(s);
-out:
-    return 0;
-} /* ds_release */
-
-/*====================================================================*/
-
-static ssize_t ds_read(struct file *file, char __user *buf,
-                      size_t count, loff_t *ppos)
-{
-    struct pcmcia_bus_socket *s;
-    user_info_t *user;
-    int ret;
-
-    ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_dentry->d_inode));
-    
-    if (count < 4)
-       return -EINVAL;
-
-    user = file->private_data;
-    if (CHECK_USER(user))
-       return -EIO;
-    
-    s = user->socket;
-    if (s->state & DS_SOCKET_DEAD)
-        return -EIO;
-
-    ret = wait_event_interruptible(s->queue, !queue_empty(user));
-    if (ret == 0)
-       ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4;
-
-    return ret;
-} /* ds_read */
-
-/*====================================================================*/
-
-static ssize_t ds_write(struct file *file, const char __user *buf,
-                       size_t count, loff_t *ppos)
-{
-    ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_dentry->d_inode));
-
-    if (count != 4)
-       return -EINVAL;
-    if ((file->f_flags & O_ACCMODE) == O_RDONLY)
-       return -EBADF;
-
-    return -EIO;
-} /* ds_write */
-
-/*====================================================================*/
-
-/* No kernel lock - fine */
-static u_int ds_poll(struct file *file, poll_table *wait)
-{
-    struct pcmcia_bus_socket *s;
-    user_info_t *user;
-
-    ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_dentry->d_inode));
-    
-    user = file->private_data;
-    if (CHECK_USER(user))
-       return POLLERR;
-    s = user->socket;
-    /*
-     * We don't check for a dead socket here since that
-     * will send cardmgr into an endless spin.
-     */
-    poll_wait(file, &s->queue, wait);
-    if (!queue_empty(user))
-       return POLLIN | POLLRDNORM;
-    return 0;
-} /* ds_poll */
-
-/*====================================================================*/
-
-extern int pcmcia_adjust_resource_info(adjust_t *adj);
-
-static int ds_ioctl(struct inode * inode, struct file * file,
-                   u_int cmd, u_long arg)
-{
-    struct pcmcia_bus_socket *s;
-    void __user *uarg = (char __user *)arg;
-    u_int size;
-    int ret, err;
-    ds_ioctl_arg_t *buf;
-    user_info_t *user;
-
-    ds_dbg(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg);
-    
-    user = file->private_data;
-    if (CHECK_USER(user))
-       return -EIO;
-
-    s = user->socket;
-    if (s->state & DS_SOCKET_DEAD)
-        return -EIO;
-    
-    size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
-    if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
-
-    /* Permission check */
-    if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN))
-       return -EPERM;
-       
-    if (cmd & IOC_IN) {
-       if (!access_ok(VERIFY_READ, uarg, size)) {
-           ds_dbg(3, "ds_ioctl(): verify_read = %d\n", -EFAULT);
-           return -EFAULT;
-       }
-    }
-    if (cmd & IOC_OUT) {
-       if (!access_ok(VERIFY_WRITE, uarg, size)) {
-           ds_dbg(3, "ds_ioctl(): verify_write = %d\n", -EFAULT);
-           return -EFAULT;
-       }
-    }
-    buf = kmalloc(sizeof(ds_ioctl_arg_t), GFP_KERNEL);
-    if (!buf)
-       return -ENOMEM;
-    
-    err = ret = 0;
-    
-    if (cmd & IOC_IN) __copy_from_user((char *)buf, uarg, size);
-    
-    switch (cmd) {
-    case DS_ADJUST_RESOURCE_INFO:
-       ret = pcmcia_adjust_resource_info(&buf->adjust);
-       break;
-    case DS_GET_CARD_SERVICES_INFO:
-       ret = pcmcia_get_card_services_info(&buf->servinfo);
-       break;
-    case DS_GET_CONFIGURATION_INFO:
-       if (buf->config.Function &&
-          (buf->config.Function >= s->parent->functions))
-           ret = CS_BAD_ARGS;
-       else
-           ret = pccard_get_configuration_info(s->parent,
-                       buf->config.Function, &buf->config);
-       break;
-    case DS_GET_FIRST_TUPLE:
-       down(&s->parent->skt_sem);
-       pcmcia_validate_mem(s->parent);
-       up(&s->parent->skt_sem);
-       ret = pccard_get_first_tuple(s->parent, BIND_FN_ALL, &buf->tuple);
-       break;
-    case DS_GET_NEXT_TUPLE:
-       ret = pccard_get_next_tuple(s->parent, BIND_FN_ALL, &buf->tuple);
-       break;
-    case DS_GET_TUPLE_DATA:
-       buf->tuple.TupleData = buf->tuple_parse.data;
-       buf->tuple.TupleDataMax = sizeof(buf->tuple_parse.data);
-       ret = pccard_get_tuple_data(s->parent, &buf->tuple);
-       break;
-    case DS_PARSE_TUPLE:
-       buf->tuple.TupleData = buf->tuple_parse.data;
-       ret = pccard_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
-       break;
-    case DS_RESET_CARD:
-       ret = pccard_reset_card(s->parent);
-       break;
-    case DS_GET_STATUS:
-       if (buf->status.Function &&
-          (buf->status.Function >= s->parent->functions))
-           ret = CS_BAD_ARGS;
-       else
-       ret = pccard_get_status(s->parent, buf->status.Function, &buf->status);
-       break;
-    case DS_VALIDATE_CIS:
-       down(&s->parent->skt_sem);
-       pcmcia_validate_mem(s->parent);
-       up(&s->parent->skt_sem);
-       ret = pccard_validate_cis(s->parent, BIND_FN_ALL, &buf->cisinfo);
-       break;
-    case DS_SUSPEND_CARD:
-       ret = pcmcia_suspend_card(s->parent);
-       break;
-    case DS_RESUME_CARD:
-       ret = pcmcia_resume_card(s->parent);
-       break;
-    case DS_EJECT_CARD:
-       err = pcmcia_eject_card(s->parent);
-       break;
-    case DS_INSERT_CARD:
-       err = pcmcia_insert_card(s->parent);
-       break;
-    case DS_ACCESS_CONFIGURATION_REGISTER:
-       if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) {
-           err = -EPERM;
-           goto free_out;
-       }
-       if (buf->conf_reg.Function &&
-          (buf->conf_reg.Function >= s->parent->functions))
-           ret = CS_BAD_ARGS;
-       else
-           ret = pccard_access_configuration_register(s->parent,
-                       buf->conf_reg.Function, &buf->conf_reg);
-       break;
-    case DS_GET_FIRST_REGION:
-    case DS_GET_NEXT_REGION:
-    case DS_BIND_MTD:
-       if (!capable(CAP_SYS_ADMIN)) {
-               err = -EPERM;
-               goto free_out;
-       } else {
-               static int printed = 0;
-               if (!printed) {
-                       printk(KERN_WARNING "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
-                       printk(KERN_WARNING "MTD handling any more.\n");
-                       printed++;
-               }
-       }
-       err = -EINVAL;
-       goto free_out;
-       break;
-    case DS_GET_FIRST_WINDOW:
-       ret = pcmcia_get_window(s->parent, &buf->win_info.handle, 0,
-                       &buf->win_info.window);
-       break;
-    case DS_GET_NEXT_WINDOW:
-       ret = pcmcia_get_window(s->parent, &buf->win_info.handle,
-                       buf->win_info.handle->index + 1, &buf->win_info.window);
-       break;
-    case DS_GET_MEM_PAGE:
-       ret = pcmcia_get_mem_page(buf->win_info.handle,
-                          &buf->win_info.map);
-       break;
-    case DS_REPLACE_CIS:
-       ret = pcmcia_replace_cis(s->parent, &buf->cisdump);
-       break;
-    case DS_BIND_REQUEST:
-       if (!capable(CAP_SYS_ADMIN)) {
-               err = -EPERM;
-               goto free_out;
-       }
-       err = bind_request(s, &buf->bind_info);
-       break;
-    case DS_GET_DEVICE_INFO:
-       err = get_device_info(s, &buf->bind_info, 1);
-       break;
-    case DS_GET_NEXT_DEVICE:
-       err = get_device_info(s, &buf->bind_info, 0);
-       break;
-    case DS_UNBIND_REQUEST:
-       err = 0;
-       break;
-    default:
-       err = -EINVAL;
-    }
-    
-    if ((err == 0) && (ret != CS_SUCCESS)) {
-       ds_dbg(2, "ds_ioctl: ret = %d\n", ret);
-       switch (ret) {
-       case CS_BAD_SOCKET: case CS_NO_CARD:
-           err = -ENODEV; break;
-       case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ:
-       case CS_BAD_TUPLE:
-           err = -EINVAL; break;
-       case CS_IN_USE:
-           err = -EBUSY; break;
-       case CS_OUT_OF_RESOURCE:
-           err = -ENOSPC; break;
-       case CS_NO_MORE_ITEMS:
-           err = -ENODATA; break;
-       case CS_UNSUPPORTED_FUNCTION:
-           err = -ENOSYS; break;
-       default:
-           err = -EIO; break;
-       }
-    }
-
-    if (cmd & IOC_OUT) {
-        if (__copy_to_user(uarg, (char *)buf, size))
-            err = -EFAULT;
-    }
-
-free_out:
-    kfree(buf);
-    return err;
-} /* ds_ioctl */
-
-/*====================================================================*/
-
-static struct file_operations ds_fops = {
-       .owner          = THIS_MODULE,
-       .open           = ds_open,
-       .release        = ds_release,
-       .ioctl          = ds_ioctl,
-       .read           = ds_read,
-       .write          = ds_write,
-       .poll           = ds_poll,
+static struct pcmcia_callback pcmcia_bus_callback = {
+       .owner = THIS_MODULE,
+       .event = ds_event,
+       .requery = pcmcia_bus_rescan,
 };
 
 static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev)
 {
        struct pcmcia_socket *socket = class_get_devdata(class_dev);
-       struct pcmcia_bus_socket *s;
        int ret;
 
-       s = kmalloc(sizeof(struct pcmcia_bus_socket), GFP_KERNEL);
-       if(!s)
-               return -ENOMEM;
-       memset(s, 0, sizeof(struct pcmcia_bus_socket));
-
-       /* get reference to parent socket */
-       s->parent = pcmcia_get_socket(socket);
-       if (!s->parent) {
+       socket = pcmcia_get_socket(socket);
+       if (!socket) {
                printk(KERN_ERR "PCMCIA obtaining reference to socket %p failed\n", socket);
-               kfree (s);
                return -ENODEV;
        }
 
-       kref_init(&s->refcount);
-    
        /*
         * Ugly. But we want to wait for the socket threads to have started up.
         * We really should let the drivers themselves drive some of this..
         */
        msleep(250);
 
-       init_waitqueue_head(&s->queue);
-       INIT_LIST_HEAD(&s->devices_list);
-
-       /* Set up hotline to Card Services */
-       s->callback.owner = THIS_MODULE;
-       s->callback.event = &ds_event;
-       s->callback.resources_done = &pcmcia_card_add;
-       socket->pcmcia = s;
+#ifdef CONFIG_PCMCIA_IOCTL
+       init_waitqueue_head(&socket->queue);
+#endif
+       INIT_LIST_HEAD(&socket->devices_list);
+       INIT_WORK(&socket->device_add, pcmcia_delayed_add_pseudo_device, socket);
+       memset(&socket->pcmcia_state, 0, sizeof(u8));
+       socket->device_count = 0;
 
-       ret = pccard_register_pcmcia(socket, &s->callback);
+       ret = pccard_register_pcmcia(socket, &pcmcia_bus_callback);
        if (ret) {
                printk(KERN_ERR "PCMCIA registration PCCard core failed for socket %p\n", socket);
-               pcmcia_put_bus_socket(s);
-               socket->pcmcia = NULL;
+               pcmcia_put_socket(socket);
                return (ret);
        }
 
        return 0;
 }
 
-
 static void pcmcia_bus_remove_socket(struct class_device *class_dev)
 {
        struct pcmcia_socket *socket = class_get_devdata(class_dev);
 
-       if (!socket || !socket->pcmcia)
+       if (!socket)
                return;
 
+       socket->pcmcia_state.dead = 1;
        pccard_register_pcmcia(socket, NULL);
 
-       socket->pcmcia->state |= DS_SOCKET_DEAD;
-       pcmcia_put_bus_socket(socket->pcmcia);
-       socket->pcmcia = NULL;
+       pcmcia_put_socket(socket);
 
        return;
 }
@@ -1575,34 +1209,20 @@ static struct class_interface pcmcia_bus_interface = {
 
 struct bus_type pcmcia_bus_type = {
        .name = "pcmcia",
+       .hotplug = pcmcia_bus_hotplug,
        .match = pcmcia_bus_match,
        .dev_attrs = pcmcia_dev_attrs,
 };
-EXPORT_SYMBOL(pcmcia_bus_type);
 
 
 static int __init init_pcmcia_bus(void)
 {
-       int i;
-
        spin_lock_init(&pcmcia_dev_list_lock);
 
        bus_register(&pcmcia_bus_type);
        class_interface_register(&pcmcia_bus_interface);
 
-       /* Set up character device for user mode clients */
-       i = register_chrdev(0, "pcmcia", &ds_fops);
-       if (i < 0)
-               printk(KERN_NOTICE "unable to find a free device # for "
-                      "Driver Services (error=%d)\n", i);
-       else
-               major_dev = i;
-
-#ifdef CONFIG_PROC_FS
-       proc_pccard = proc_mkdir("pccard", proc_bus);
-       if (proc_pccard)
-               create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL);
-#endif
+       pcmcia_setup_ioctl();
 
        return 0;
 }
@@ -1612,48 +1232,13 @@ fs_initcall(init_pcmcia_bus); /* one level after subsys_initcall so that
 
 static void __exit exit_pcmcia_bus(void)
 {
-       class_interface_unregister(&pcmcia_bus_interface);
+       pcmcia_cleanup_ioctl();
 
-#ifdef CONFIG_PROC_FS
-       if (proc_pccard) {
-               remove_proc_entry("drivers", proc_pccard);
-               remove_proc_entry("pccard", proc_bus);
-       }
-#endif
-       if (major_dev != -1)
-               unregister_chrdev(major_dev, "pcmcia");
+       class_interface_unregister(&pcmcia_bus_interface);
 
        bus_unregister(&pcmcia_bus_type);
 }
 module_exit(exit_pcmcia_bus);
 
 
-
-/* helpers for backwards-compatible functions */
-
-static struct pcmcia_bus_socket * get_socket_info_by_nr(unsigned int nr)
-{
-       struct pcmcia_socket * s = pcmcia_get_socket_by_nr(nr);
-       if (s && s->pcmcia)
-               return s->pcmcia;
-       else
-               return NULL;
-}
-
-/* backwards-compatible accessing of driver --- by name! */
-
-static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info)
-{
-       struct device_driver *drv;
-       struct pcmcia_driver *p_drv;
-
-       drv = driver_find((char *) dev_info, &pcmcia_bus_type);
-       if (!drv)
-               return NULL;
-
-       p_drv = container_of(drv, struct pcmcia_driver, drv);
-
-       return (p_drv);
-}
-
 MODULE_ALIAS("ds");
diff --git a/drivers/pcmcia/ds_internal.h b/drivers/pcmcia/ds_internal.h
new file mode 100644 (file)
index 0000000..d359bd2
--- /dev/null
@@ -0,0 +1,21 @@
+/* ds_internal.h - internal header for 16-bit PCMCIA devices management */
+
+extern spinlock_t pcmcia_dev_list_lock;
+extern struct bus_type pcmcia_bus_type;
+
+extern struct pcmcia_device * pcmcia_get_dev(struct pcmcia_device *p_dev);
+extern void pcmcia_put_dev(struct pcmcia_device *p_dev);
+
+struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int function);
+
+#ifdef CONFIG_PCMCIA_IOCTL
+extern void __init pcmcia_setup_ioctl(void);
+extern void __exit pcmcia_cleanup_ioctl(void);
+extern void handle_event(struct pcmcia_socket *s, event_t event);
+extern int handle_request(struct pcmcia_socket *s, event_t event);
+#else
+static inline void __init pcmcia_setup_ioctl(void) { return; }
+static inline void __init pcmcia_cleanup_ioctl(void) { return; }
+static inline void handle_event(struct pcmcia_socket *s, event_t event) { return; }
+static inline int handle_request(struct pcmcia_socket *s, event_t event) { return CS_SUCCESS; }
+#endif
index 90a335a..d72f9a3 100644 (file)
@@ -669,11 +669,13 @@ static int __init is_alive(u_short sock)
     if ((stat & I365_CS_DETECT) && (stat & I365_CS_POWERON) &&
        (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD) &&
        (i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(0)) &&
-       (check_region(start, stop-start+1) != 0) &&
-       ((start & 0xfeef) != 0x02e8))
-       return 1;
-    else
-       return 0;
+       ((start & 0xfeef) != 0x02e8)) {
+       if (!request_region(start, stop-start+1, "i82365"))
+           return 1;
+       release_region(start, stop-start+1);
+    }
+
+    return 0;
 }
 
 /*====================================================================*/
@@ -696,7 +698,13 @@ static void __init add_pcic(int ns, int type)
     struct i82365_socket *t = &socket[sockets-ns];
 
     base = sockets-ns;
-    if (t->ioaddr > 0) request_region(t->ioaddr, 2, "i82365");
+    if (t->ioaddr > 0) {
+       if (!request_region(t->ioaddr, 2, "i82365")) {
+           printk(KERN_ERR "i82365: IO region conflict at %#lx, not available\n",
+                       t->ioaddr);
+           return;
+       }
+    }
     
     if (base == 0) printk("\n");
     printk(KERN_INFO "  %s", pcic[type].name);
@@ -803,7 +811,7 @@ static void __init isa_probe(void)
     }
 #endif
 
-    if (check_region(i365_base, 2) != 0) {
+    if (!request_region(i365_base, 2, "i82365")) {
        if (sockets == 0)
            printk("port conflict at %#lx\n", i365_base);
        return;
@@ -1441,6 +1449,7 @@ static void __exit exit_i82365(void)
        i365_set(i, I365_CSCINT, 0);
        release_region(socket[i].ioaddr, 2);
     }
+    release_region(i365_base, 2);
 #ifdef CONFIG_PNP
     if (i82365_pnpdev)
                pnp_disable_dev(i82365_pnpdev);
index 68b8008..1cc8331 100644 (file)
@@ -74,19 +74,6 @@ int pcmcia_validate_cis(client_handle_t handle, cisinfo_t *info)
 }
 EXPORT_SYMBOL(pcmcia_validate_cis);
 
-int pcmcia_get_configuration_info(client_handle_t handle,
-                                 config_info_t *config)
-{
-       struct pcmcia_socket *s;
-
-       if ((CHECK_HANDLE(handle)) || !config)
-               return CS_BAD_HANDLE;
-       s = SOCKET(handle);
-       if (!s)
-               return CS_BAD_HANDLE;
-       return pccard_get_configuration_info(s, handle->Function, config);
-}
-EXPORT_SYMBOL(pcmcia_get_configuration_info);
 
 int pcmcia_reset_card(client_handle_t handle, client_req_t *req)
 {
@@ -102,24 +89,3 @@ int pcmcia_reset_card(client_handle_t handle, client_req_t *req)
 }
 EXPORT_SYMBOL(pcmcia_reset_card);
 
-int pcmcia_get_status(client_handle_t handle, cs_status_t *status)
-{
-       struct pcmcia_socket *s;
-       if (CHECK_HANDLE(handle))
-               return CS_BAD_HANDLE;
-       s = SOCKET(handle);
-       return pccard_get_status(s, handle->Function, status);
-}
-EXPORT_SYMBOL(pcmcia_get_status);
-
-int pcmcia_access_configuration_register(client_handle_t handle,
-                                        conf_reg_t *reg)
-{
-       struct pcmcia_socket *s;
-       if (CHECK_HANDLE(handle))
-               return CS_BAD_HANDLE;
-       s = SOCKET(handle);
-       return pccard_access_configuration_register(s, handle->Function, reg);
-}
-EXPORT_SYMBOL(pcmcia_access_configuration_register);
-
diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c
new file mode 100644 (file)
index 0000000..b883bc1
--- /dev/null
@@ -0,0 +1,786 @@
+/*
+ * pcmcia_ioctl.c -- ioctl interface for cardmgr and cardctl
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * (C) 1999            David A. Hinds
+ * (C) 2003 - 2004     Dominik Brodowski
+ */
+
+/*
+ * This file will go away soon.
+ */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/proc_fs.h>
+#include <linux/poll.h>
+#include <linux/pci.h>
+#include <linux/workqueue.h>
+
+#define IN_CARD_SERVICES
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/ss.h>
+
+#include "cs_internal.h"
+#include "ds_internal.h"
+
+static int major_dev = -1;
+
+
+/* Device user information */
+#define MAX_EVENTS     32
+#define USER_MAGIC     0x7ea4
+#define CHECK_USER(u) \
+    (((u) == NULL) || ((u)->user_magic != USER_MAGIC))
+
+typedef struct user_info_t {
+       u_int                   user_magic;
+       int                     event_head, event_tail;
+       event_t                 event[MAX_EVENTS];
+       struct user_info_t      *next;
+       struct pcmcia_socket    *socket;
+} user_info_t;
+
+
+#ifdef DEBUG
+extern int ds_pc_debug;
+#define cs_socket_name(skt)    ((skt)->dev.class_id)
+
+#define ds_dbg(lvl, fmt, arg...) do {          \
+       if (ds_pc_debug >= lvl)                         \
+               printk(KERN_DEBUG "ds: " fmt , ## arg);         \
+} while (0)
+#else
+#define ds_dbg(lvl, fmt, arg...) do { } while (0)
+#endif
+
+static const char *release = "Linux Kernel Card Services";
+
+/** pcmcia_get_card_services_info
+ *
+ * Return information about this version of Card Services
+ */
+static int pcmcia_get_card_services_info(servinfo_t *info)
+{
+       unsigned int socket_count = 0;
+       struct list_head *tmp;
+       info->Signature[0] = 'C';
+       info->Signature[1] = 'S';
+       down_read(&pcmcia_socket_list_rwsem);
+       list_for_each(tmp, &pcmcia_socket_list)
+               socket_count++;
+       up_read(&pcmcia_socket_list_rwsem);
+       info->Count = socket_count;
+       info->Revision = CS_RELEASE_CODE;
+       info->CSLevel = 0x0210;
+       info->VendorString = (char *)release;
+       return CS_SUCCESS;
+} /* get_card_services_info */
+
+
+/* backwards-compatible accessing of driver --- by name! */
+
+static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info)
+{
+       struct device_driver *drv;
+       struct pcmcia_driver *p_drv;
+
+       drv = driver_find((char *) dev_info, &pcmcia_bus_type);
+       if (!drv)
+               return NULL;
+
+       p_drv = container_of(drv, struct pcmcia_driver, drv);
+
+       return (p_drv);
+}
+
+
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry *proc_pccard = NULL;
+
+static int proc_read_drivers_callback(struct device_driver *driver, void *d)
+{
+       char **p = d;
+       struct pcmcia_driver *p_drv = container_of(driver,
+                                                  struct pcmcia_driver, drv);
+
+       *p += sprintf(*p, "%-24.24s 1 %d\n", p_drv->drv.name,
+#ifdef CONFIG_MODULE_UNLOAD
+                     (p_drv->owner) ? module_refcount(p_drv->owner) : 1
+#else
+                     1
+#endif
+       );
+       d = (void *) p;
+
+       return 0;
+}
+
+static int proc_read_drivers(char *buf, char **start, off_t pos,
+                            int count, int *eof, void *data)
+{
+       char *p = buf;
+
+       bus_for_each_drv(&pcmcia_bus_type, NULL,
+                        (void *) &p, proc_read_drivers_callback);
+
+       return (p - buf);
+}
+#endif
+
+/*======================================================================
+
+    These manage a ring buffer of events pending for one user process
+
+======================================================================*/
+
+
+static int queue_empty(user_info_t *user)
+{
+    return (user->event_head == user->event_tail);
+}
+
+static event_t get_queued_event(user_info_t *user)
+{
+    user->event_tail = (user->event_tail+1) % MAX_EVENTS;
+    return user->event[user->event_tail];
+}
+
+static void queue_event(user_info_t *user, event_t event)
+{
+    user->event_head = (user->event_head+1) % MAX_EVENTS;
+    if (user->event_head == user->event_tail)
+       user->event_tail = (user->event_tail+1) % MAX_EVENTS;
+    user->event[user->event_head] = event;
+}
+
+void handle_event(struct pcmcia_socket *s, event_t event)
+{
+    user_info_t *user;
+    for (user = s->user; user; user = user->next)
+       queue_event(user, event);
+    wake_up_interruptible(&s->queue);
+}
+
+
+/*======================================================================
+
+    bind_request() and bind_device() are merged by now. Register_client()
+    is called right at the end of bind_request(), during the driver's
+    ->attach() call. Individual descriptions:
+
+    bind_request() connects a socket to a particular client driver.
+    It looks up the specified device ID in the list of registered
+    drivers, binds it to the socket, and tries to create an instance
+    of the device.  unbind_request() deletes a driver instance.
+
+    Bind_device() associates a device driver with a particular socket.
+    It is normally called by Driver Services after it has identified
+    a newly inserted card.  An instance of that driver will then be
+    eligible to register as a client of this socket.
+
+    Register_client() uses the dev_info_t handle to match the
+    caller with a socket.  The driver must have already been bound
+    to a socket with bind_device() -- in fact, bind_device()
+    allocates the client structure that will be used.
+
+======================================================================*/
+
+static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info)
+{
+       struct pcmcia_driver *p_drv;
+       struct pcmcia_device *p_dev;
+       int ret = 0;
+       unsigned long flags;
+
+       s = pcmcia_get_socket(s);
+       if (!s)
+               return -EINVAL;
+
+       ds_dbg(2, "bind_request(%d, '%s')\n", s->sock,
+              (char *)bind_info->dev_info);
+
+       p_drv = get_pcmcia_driver(&bind_info->dev_info);
+       if (!p_drv) {
+               ret = -EINVAL;
+               goto err_put;
+       }
+
+       if (!try_module_get(p_drv->owner)) {
+               ret = -EINVAL;
+               goto err_put_driver;
+       }
+
+       spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+        list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
+               if (p_dev->func == bind_info->function) {
+                       if ((p_dev->dev.driver == &p_drv->drv)) {
+                               if (p_dev->cardmgr) {
+                                       /* if there's already a device
+                                        * registered, and it was registered
+                                        * by userspace before, we need to
+                                        * return the "instance". */
+                                       spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+                                       bind_info->instance = p_dev->instance;
+                                       ret = -EBUSY;
+                                       goto err_put_module;
+                               } else {
+                                       /* the correct driver managed to bind
+                                        * itself magically to the correct
+                                        * device. */
+                                       spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+                                       p_dev->cardmgr = p_drv;
+                                       ret = 0;
+                                       goto err_put_module;
+                               }
+                       } else if (!p_dev->dev.driver) {
+                               /* there's already a device available where
+                                * no device has been bound to yet. So we don't
+                                * need to register a device! */
+                               spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+                               goto rescan;
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+
+       p_dev = pcmcia_device_add(s, bind_info->function);
+       if (!p_dev) {
+               ret = -EIO;
+               goto err_put_module;
+       }
+
+rescan:
+       p_dev->cardmgr = p_drv;
+
+       /* if a driver is already running, we can abort */
+       if (p_dev->dev.driver)
+               goto err_put_module;
+
+       /*
+        * Prevent this racing with a card insertion.
+        */
+       down(&s->skt_sem);
+       bus_rescan_devices(&pcmcia_bus_type);
+       up(&s->skt_sem);
+
+       /* check whether the driver indeed matched. I don't care if this
+        * is racy or not, because it can only happen on cardmgr access
+        * paths...
+        */
+       if (!(p_dev->dev.driver == &p_drv->drv))
+               p_dev->cardmgr = NULL;
+
+ err_put_module:
+       module_put(p_drv->owner);
+ err_put_driver:
+       put_driver(&p_drv->drv);
+ err_put:
+       pcmcia_put_socket(s);
+
+       return (ret);
+} /* bind_request */
+
+#ifdef CONFIG_CARDBUS
+
+static struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s)
+{
+       if (!s || !(s->state & SOCKET_CARDBUS))
+               return NULL;
+
+       return s->cb_dev->subordinate;
+}
+#endif
+
+static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int first)
+{
+       dev_node_t *node;
+       struct pcmcia_device *p_dev;
+       unsigned long flags;
+       int ret = 0;
+
+#ifdef CONFIG_CARDBUS
+       /*
+        * Some unbelievably ugly code to associate the PCI cardbus
+        * device and its driver with the PCMCIA "bind" information.
+        */
+       {
+               struct pci_bus *bus;
+
+               bus = pcmcia_lookup_bus(s);
+               if (bus) {
+                       struct list_head *list;
+                       struct pci_dev *dev = NULL;
+
+                       list = bus->devices.next;
+                       while (list != &bus->devices) {
+                               struct pci_dev *pdev = pci_dev_b(list);
+                               list = list->next;
+
+                               if (first) {
+                                       dev = pdev;
+                                       break;
+                               }
+
+                               /* Try to handle "next" here some way? */
+                       }
+                       if (dev && dev->driver) {
+                               strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN);
+                               bind_info->major = 0;
+                               bind_info->minor = 0;
+                               bind_info->next = NULL;
+                               return 0;
+                       }
+               }
+       }
+#endif
+
+       spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+       list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
+               if (p_dev->func == bind_info->function) {
+                       p_dev = pcmcia_get_dev(p_dev);
+                       if (!p_dev)
+                               continue;
+                       goto found;
+               }
+       }
+       spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+       return -ENODEV;
+
+ found:
+       spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+
+       if ((!p_dev->instance) ||
+           (p_dev->instance->state & DEV_CONFIG_PENDING)) {
+               ret = -EAGAIN;
+               goto err_put;
+       }
+
+       if (first)
+               node = p_dev->instance->dev;
+       else
+               for (node = p_dev->instance->dev; node; node = node->next)
+                       if (node == bind_info->next)
+                               break;
+       if (!node) {
+               ret = -ENODEV;
+               goto err_put;
+       }
+
+       strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
+       bind_info->major = node->major;
+       bind_info->minor = node->minor;
+       bind_info->next = node->next;
+
+ err_put:
+       pcmcia_put_dev(p_dev);
+       return (ret);
+} /* get_device_info */
+
+
+static int ds_open(struct inode *inode, struct file *file)
+{
+    socket_t i = iminor(inode);
+    struct pcmcia_socket *s;
+    user_info_t *user;
+
+    ds_dbg(0, "ds_open(socket %d)\n", i);
+
+    s = pcmcia_get_socket_by_nr(i);
+    if (!s)
+           return -ENODEV;
+    s = pcmcia_get_socket(s);
+    if (!s)
+           return -ENODEV;
+
+    if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+           if (s->pcmcia_state.busy) {
+                   pcmcia_put_socket(s);
+                   return -EBUSY;
+           }
+       else
+           s->pcmcia_state.busy = 1;
+    }
+
+    user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
+    if (!user) {
+           pcmcia_put_socket(s);
+           return -ENOMEM;
+    }
+    user->event_tail = user->event_head = 0;
+    user->next = s->user;
+    user->user_magic = USER_MAGIC;
+    user->socket = s;
+    s->user = user;
+    file->private_data = user;
+
+    if (s->pcmcia_state.present)
+       queue_event(user, CS_EVENT_CARD_INSERTION);
+    return 0;
+} /* ds_open */
+
+/*====================================================================*/
+
+static int ds_release(struct inode *inode, struct file *file)
+{
+    struct pcmcia_socket *s;
+    user_info_t *user, **link;
+
+    ds_dbg(0, "ds_release(socket %d)\n", iminor(inode));
+
+    user = file->private_data;
+    if (CHECK_USER(user))
+       goto out;
+
+    s = user->socket;
+
+    /* Unlink user data structure */
+    if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+       s->pcmcia_state.busy = 0;
+    }
+    file->private_data = NULL;
+    for (link = &s->user; *link; link = &(*link)->next)
+       if (*link == user) break;
+    if (link == NULL)
+       goto out;
+    *link = user->next;
+    user->user_magic = 0;
+    kfree(user);
+    pcmcia_put_socket(s);
+out:
+    return 0;
+} /* ds_release */
+
+/*====================================================================*/
+
+static ssize_t ds_read(struct file *file, char __user *buf,
+                      size_t count, loff_t *ppos)
+{
+    struct pcmcia_socket *s;
+    user_info_t *user;
+    int ret;
+
+    ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_dentry->d_inode));
+
+    if (count < 4)
+       return -EINVAL;
+
+    user = file->private_data;
+    if (CHECK_USER(user))
+       return -EIO;
+
+    s = user->socket;
+    if (s->pcmcia_state.dead)
+        return -EIO;
+
+    ret = wait_event_interruptible(s->queue, !queue_empty(user));
+    if (ret == 0)
+       ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4;
+
+    return ret;
+} /* ds_read */
+
+/*====================================================================*/
+
+static ssize_t ds_write(struct file *file, const char __user *buf,
+                       size_t count, loff_t *ppos)
+{
+    ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_dentry->d_inode));
+
+    if (count != 4)
+       return -EINVAL;
+    if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+       return -EBADF;
+
+    return -EIO;
+} /* ds_write */
+
+/*====================================================================*/
+
+/* No kernel lock - fine */
+static u_int ds_poll(struct file *file, poll_table *wait)
+{
+    struct pcmcia_socket *s;
+    user_info_t *user;
+
+    ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_dentry->d_inode));
+
+    user = file->private_data;
+    if (CHECK_USER(user))
+       return POLLERR;
+    s = user->socket;
+    /*
+     * We don't check for a dead socket here since that
+     * will send cardmgr into an endless spin.
+     */
+    poll_wait(file, &s->queue, wait);
+    if (!queue_empty(user))
+       return POLLIN | POLLRDNORM;
+    return 0;
+} /* ds_poll */
+
+/*====================================================================*/
+
+extern int pcmcia_adjust_resource_info(adjust_t *adj);
+
+static int ds_ioctl(struct inode * inode, struct file * file,
+                   u_int cmd, u_long arg)
+{
+    struct pcmcia_socket *s;
+    void __user *uarg = (char __user *)arg;
+    u_int size;
+    int ret, err;
+    ds_ioctl_arg_t *buf;
+    user_info_t *user;
+
+    ds_dbg(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg);
+
+    user = file->private_data;
+    if (CHECK_USER(user))
+       return -EIO;
+
+    s = user->socket;
+    if (s->pcmcia_state.dead)
+        return -EIO;
+
+    size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
+    if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
+
+    /* Permission check */
+    if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN))
+       return -EPERM;
+
+    if (cmd & IOC_IN) {
+       if (!access_ok(VERIFY_READ, uarg, size)) {
+           ds_dbg(3, "ds_ioctl(): verify_read = %d\n", -EFAULT);
+           return -EFAULT;
+       }
+    }
+    if (cmd & IOC_OUT) {
+       if (!access_ok(VERIFY_WRITE, uarg, size)) {
+           ds_dbg(3, "ds_ioctl(): verify_write = %d\n", -EFAULT);
+           return -EFAULT;
+       }
+    }
+    buf = kmalloc(sizeof(ds_ioctl_arg_t), GFP_KERNEL);
+    if (!buf)
+       return -ENOMEM;
+
+    err = ret = 0;
+
+    if (cmd & IOC_IN) __copy_from_user((char *)buf, uarg, size);
+
+    switch (cmd) {
+    case DS_ADJUST_RESOURCE_INFO:
+       ret = pcmcia_adjust_resource_info(&buf->adjust);
+       break;
+    case DS_GET_CARD_SERVICES_INFO:
+       ret = pcmcia_get_card_services_info(&buf->servinfo);
+       break;
+    case DS_GET_CONFIGURATION_INFO:
+       if (buf->config.Function &&
+          (buf->config.Function >= s->functions))
+           ret = CS_BAD_ARGS;
+       else
+           ret = pccard_get_configuration_info(s,
+                       buf->config.Function, &buf->config);
+       break;
+    case DS_GET_FIRST_TUPLE:
+       down(&s->skt_sem);
+       pcmcia_validate_mem(s);
+       up(&s->skt_sem);
+       ret = pccard_get_first_tuple(s, BIND_FN_ALL, &buf->tuple);
+       break;
+    case DS_GET_NEXT_TUPLE:
+       ret = pccard_get_next_tuple(s, BIND_FN_ALL, &buf->tuple);
+       break;
+    case DS_GET_TUPLE_DATA:
+       buf->tuple.TupleData = buf->tuple_parse.data;
+       buf->tuple.TupleDataMax = sizeof(buf->tuple_parse.data);
+       ret = pccard_get_tuple_data(s, &buf->tuple);
+       break;
+    case DS_PARSE_TUPLE:
+       buf->tuple.TupleData = buf->tuple_parse.data;
+       ret = pccard_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
+       break;
+    case DS_RESET_CARD:
+       ret = pccard_reset_card(s);
+       break;
+    case DS_GET_STATUS:
+       if (buf->status.Function &&
+          (buf->status.Function >= s->functions))
+           ret = CS_BAD_ARGS;
+       else
+       ret = pccard_get_status(s, buf->status.Function, &buf->status);
+       break;
+    case DS_VALIDATE_CIS:
+       down(&s->skt_sem);
+       pcmcia_validate_mem(s);
+       up(&s->skt_sem);
+       ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo);
+       break;
+    case DS_SUSPEND_CARD:
+       ret = pcmcia_suspend_card(s);
+       break;
+    case DS_RESUME_CARD:
+       ret = pcmcia_resume_card(s);
+       break;
+    case DS_EJECT_CARD:
+       err = pcmcia_eject_card(s);
+       break;
+    case DS_INSERT_CARD:
+       err = pcmcia_insert_card(s);
+       break;
+    case DS_ACCESS_CONFIGURATION_REGISTER:
+       if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) {
+           err = -EPERM;
+           goto free_out;
+       }
+       if (buf->conf_reg.Function &&
+          (buf->conf_reg.Function >= s->functions))
+           ret = CS_BAD_ARGS;
+       else
+           ret = pccard_access_configuration_register(s,
+                       buf->conf_reg.Function, &buf->conf_reg);
+       break;
+    case DS_GET_FIRST_REGION:
+    case DS_GET_NEXT_REGION:
+    case DS_BIND_MTD:
+       if (!capable(CAP_SYS_ADMIN)) {
+               err = -EPERM;
+               goto free_out;
+       } else {
+               static int printed = 0;
+               if (!printed) {
+                       printk(KERN_WARNING "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
+                       printk(KERN_WARNING "MTD handling any more.\n");
+                       printed++;
+               }
+       }
+       err = -EINVAL;
+       goto free_out;
+       break;
+    case DS_GET_FIRST_WINDOW:
+       ret = pcmcia_get_window(s, &buf->win_info.handle, 0,
+                       &buf->win_info.window);
+       break;
+    case DS_GET_NEXT_WINDOW:
+       ret = pcmcia_get_window(s, &buf->win_info.handle,
+                       buf->win_info.handle->index + 1, &buf->win_info.window);
+       break;
+    case DS_GET_MEM_PAGE:
+       ret = pcmcia_get_mem_page(buf->win_info.handle,
+                          &buf->win_info.map);
+       break;
+    case DS_REPLACE_CIS:
+       ret = pcmcia_replace_cis(s, &buf->cisdump);
+       break;
+    case DS_BIND_REQUEST:
+       if (!capable(CAP_SYS_ADMIN)) {
+               err = -EPERM;
+               goto free_out;
+       }
+       err = bind_request(s, &buf->bind_info);
+       break;
+    case DS_GET_DEVICE_INFO:
+       err = get_device_info(s, &buf->bind_info, 1);
+       break;
+    case DS_GET_NEXT_DEVICE:
+       err = get_device_info(s, &buf->bind_info, 0);
+       break;
+    case DS_UNBIND_REQUEST:
+       err = 0;
+       break;
+    default:
+       err = -EINVAL;
+    }
+
+    if ((err == 0) && (ret != CS_SUCCESS)) {
+       ds_dbg(2, "ds_ioctl: ret = %d\n", ret);
+       switch (ret) {
+       case CS_BAD_SOCKET: case CS_NO_CARD:
+           err = -ENODEV; break;
+       case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ:
+       case CS_BAD_TUPLE:
+           err = -EINVAL; break;
+       case CS_IN_USE:
+           err = -EBUSY; break;
+       case CS_OUT_OF_RESOURCE:
+           err = -ENOSPC; break;
+       case CS_NO_MORE_ITEMS:
+           err = -ENODATA; break;
+       case CS_UNSUPPORTED_FUNCTION:
+           err = -ENOSYS; break;
+       default:
+           err = -EIO; break;
+       }
+    }
+
+    if (cmd & IOC_OUT) {
+        if (__copy_to_user(uarg, (char *)buf, size))
+            err = -EFAULT;
+    }
+
+free_out:
+    kfree(buf);
+    return err;
+} /* ds_ioctl */
+
+/*====================================================================*/
+
+static struct file_operations ds_fops = {
+       .owner          = THIS_MODULE,
+       .open           = ds_open,
+       .release        = ds_release,
+       .ioctl          = ds_ioctl,
+       .read           = ds_read,
+       .write          = ds_write,
+       .poll           = ds_poll,
+};
+
+void __init pcmcia_setup_ioctl(void) {
+       int i;
+
+       /* Set up character device for user mode clients */
+       i = register_chrdev(0, "pcmcia", &ds_fops);
+       if (i < 0)
+               printk(KERN_NOTICE "unable to find a free device # for "
+                      "Driver Services (error=%d)\n", i);
+       else
+               major_dev = i;
+
+#ifdef CONFIG_PROC_FS
+       proc_pccard = proc_mkdir("pccard", proc_bus);
+       if (proc_pccard)
+               create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL);
+#endif
+}
+
+
+void __exit pcmcia_cleanup_ioctl(void) {
+#ifdef CONFIG_PROC_FS
+       if (proc_pccard) {
+               remove_proc_entry("drivers", proc_pccard);
+               remove_proc_entry("pccard", proc_bus);
+       }
+#endif
+       if (major_dev != -1)
+               unregister_chrdev(major_dev, "pcmcia");
+}
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
new file mode 100644 (file)
index 0000000..c01dc6b
--- /dev/null
@@ -0,0 +1,998 @@
+/*
+ * PCMCIA 16-bit resource management functions
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Copyright (C) 1999       David A. Hinds
+ * Copyright (C) 2004-2005   Dominik Brodowski
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/device.h>
+
+#define IN_CARD_SERVICES
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+
+#include "cs_internal.h"
+#include "ds_internal.h"
+
+
+/* Access speed for IO windows */
+static int io_speed = 0;
+module_param(io_speed, int, 0444);
+
+
+#ifdef CONFIG_PCMCIA_PROBE
+/* mask of IRQs already reserved by other cards, we should avoid using them */
+static u8 pcmcia_used_irq[NR_IRQS];
+#endif
+
+
+#ifdef DEBUG
+extern int ds_pc_debug;
+#define cs_socket_name(skt)    ((skt)->dev.class_id)
+
+#define ds_dbg(skt, lvl, fmt, arg...) do {                     \
+       if (ds_pc_debug >= lvl)                                 \
+               printk(KERN_DEBUG "pcmcia_resource: %s: " fmt,  \
+                       cs_socket_name(skt) , ## arg);          \
+} while (0)
+#else
+#define ds_dbg(lvl, fmt, arg...) do { } while (0)
+#endif
+
+
+
+/** alloc_io_space
+ *
+ * Special stuff for managing IO windows, because they are scarce
+ */
+
+static int alloc_io_space(struct pcmcia_socket *s, u_int attr, ioaddr_t *base,
+                         ioaddr_t num, u_int lines)
+{
+       int i;
+       kio_addr_t try, align;
+
+       align = (*base) ? (lines ? 1<<lines : 0) : 1;
+       if (align && (align < num)) {
+               if (*base) {
+                       ds_dbg(s, 0, "odd IO request: num %#x align %#lx\n",
+                              num, align);
+                       align = 0;
+               } else
+                       while (align && (align < num)) align <<= 1;
+       }
+       if (*base & ~(align-1)) {
+               ds_dbg(s, 0, "odd IO request: base %#x align %#lx\n",
+                      *base, align);
+               align = 0;
+       }
+       if ((s->features & SS_CAP_STATIC_MAP) && s->io_offset) {
+               *base = s->io_offset | (*base & 0x0fff);
+               s->io[0].Attributes = attr;
+               return 0;
+       }
+       /* Check for an already-allocated window that must conflict with
+        * what was asked for.  It is a hack because it does not catch all
+        * potential conflicts, just the most obvious ones.
+        */
+       for (i = 0; i < MAX_IO_WIN; i++)
+               if ((s->io[i].NumPorts != 0) &&
+                   ((s->io[i].BasePort & (align-1)) == *base))
+                       return 1;
+       for (i = 0; i < MAX_IO_WIN; i++) {
+               if (s->io[i].NumPorts == 0) {
+                       s->io[i].res = pcmcia_find_io_region(*base, num, align, s);
+                       if (s->io[i].res) {
+                               s->io[i].Attributes = attr;
+                               s->io[i].BasePort = *base = s->io[i].res->start;
+                               s->io[i].NumPorts = s->io[i].InUse = num;
+                               break;
+                       } else
+                               return 1;
+               } else if (s->io[i].Attributes != attr)
+                       continue;
+               /* Try to extend top of window */
+               try = s->io[i].BasePort + s->io[i].NumPorts;
+               if ((*base == 0) || (*base == try))
+                       if (pcmcia_adjust_io_region(s->io[i].res, s->io[i].res->start,
+                                                   s->io[i].res->end + num, s) == 0) {
+                               *base = try;
+                               s->io[i].NumPorts += num;
+                               s->io[i].InUse += num;
+                               break;
+                       }
+               /* Try to extend bottom of window */
+               try = s->io[i].BasePort - num;
+               if ((*base == 0) || (*base == try))
+                       if (pcmcia_adjust_io_region(s->io[i].res, s->io[i].res->start - num,
+                                                   s->io[i].res->end, s) == 0) {
+                               s->io[i].BasePort = *base = try;
+                               s->io[i].NumPorts += num;
+                               s->io[i].InUse += num;
+                               break;
+                       }
+       }
+       return (i == MAX_IO_WIN);
+} /* alloc_io_space */
+
+
+static void release_io_space(struct pcmcia_socket *s, ioaddr_t base,
+                            ioaddr_t num)
+{
+       int i;
+
+       for (i = 0; i < MAX_IO_WIN; i++) {
+               if ((s->io[i].BasePort <= base) &&
+                   (s->io[i].BasePort+s->io[i].NumPorts >= base+num)) {
+                       s->io[i].InUse -= num;
+                       /* Free the window if no one else is using it */
+                       if (s->io[i].InUse == 0) {
+                               s->io[i].NumPorts = 0;
+                               release_resource(s->io[i].res);
+                               kfree(s->io[i].res);
+                               s->io[i].res = NULL;
+                       }
+               }
+       }
+} /* release_io_space */
+
+
+/** pccard_access_configuration_register
+ *
+ * Access_configuration_register() reads and writes configuration
+ * registers in attribute memory.  Memory window 0 is reserved for
+ * this and the tuple reading services.
+ */
+
+int pccard_access_configuration_register(struct pcmcia_socket *s,
+                                        unsigned int function,
+                                        conf_reg_t *reg)
+{
+       config_t *c;
+       int addr;
+       u_char val;
+
+       if (!s || !s->config)
+               return CS_NO_CARD;
+
+       c = &s->config[function];
+
+       if (c == NULL)
+               return CS_NO_CARD;
+
+       if (!(c->state & CONFIG_LOCKED))
+               return CS_CONFIGURATION_LOCKED;
+
+       addr = (c->ConfigBase + reg->Offset) >> 1;
+
+       switch (reg->Action) {
+       case CS_READ:
+               pcmcia_read_cis_mem(s, 1, addr, 1, &val);
+               reg->Value = val;
+               break;
+       case CS_WRITE:
+               val = reg->Value;
+               pcmcia_write_cis_mem(s, 1, addr, 1, &val);
+               break;
+       default:
+               return CS_BAD_ARGS;
+               break;
+       }
+       return CS_SUCCESS;
+} /* pccard_access_configuration_register */
+
+int pcmcia_access_configuration_register(client_handle_t handle,
+                                        conf_reg_t *reg)
+{
+       struct pcmcia_socket *s;
+       if (CHECK_HANDLE(handle))
+               return CS_BAD_HANDLE;
+       s = SOCKET(handle);
+       return pccard_access_configuration_register(s, handle->Function, reg);
+}
+EXPORT_SYMBOL(pcmcia_access_configuration_register);
+
+
+
+int pccard_get_configuration_info(struct pcmcia_socket *s,
+                                 unsigned int function,
+                                 config_info_t *config)
+{
+       config_t *c;
+
+       if (!(s->state & SOCKET_PRESENT))
+               return CS_NO_CARD;
+
+       config->Function = function;
+
+#ifdef CONFIG_CARDBUS
+       if (s->state & SOCKET_CARDBUS) {
+               memset(config, 0, sizeof(config_info_t));
+               config->Vcc = s->socket.Vcc;
+               config->Vpp1 = config->Vpp2 = s->socket.Vpp;
+               config->Option = s->cb_dev->subordinate->number;
+               if (s->state & SOCKET_CARDBUS_CONFIG) {
+                       config->Attributes = CONF_VALID_CLIENT;
+                       config->IntType = INT_CARDBUS;
+                       config->AssignedIRQ = s->irq.AssignedIRQ;
+                       if (config->AssignedIRQ)
+                               config->Attributes |= CONF_ENABLE_IRQ;
+                       config->BasePort1 = s->io[0].BasePort;
+                       config->NumPorts1 = s->io[0].NumPorts;
+               }
+               return CS_SUCCESS;
+       }
+#endif
+
+       c = (s->config != NULL) ? &s->config[function] : NULL;
+
+       if ((c == NULL) || !(c->state & CONFIG_LOCKED)) {
+               config->Attributes = 0;
+               config->Vcc = s->socket.Vcc;
+               config->Vpp1 = config->Vpp2 = s->socket.Vpp;
+               return CS_SUCCESS;
+       }
+
+       /* !!! This is a hack !!! */
+       memcpy(&config->Attributes, &c->Attributes, sizeof(config_t));
+       config->Attributes |= CONF_VALID_CLIENT;
+       config->CardValues = c->CardValues;
+       config->IRQAttributes = c->irq.Attributes;
+       config->AssignedIRQ = s->irq.AssignedIRQ;
+       config->BasePort1 = c->io.BasePort1;
+       config->NumPorts1 = c->io.NumPorts1;
+       config->Attributes1 = c->io.Attributes1;
+       config->BasePort2 = c->io.BasePort2;
+       config->NumPorts2 = c->io.NumPorts2;
+       config->Attributes2 = c->io.Attributes2;
+       config->IOAddrLines = c->io.IOAddrLines;
+
+       return CS_SUCCESS;
+} /* pccard_get_configuration_info */
+
+int pcmcia_get_configuration_info(client_handle_t handle,
+                                 config_info_t *config)
+{
+       struct pcmcia_socket *s;
+
+       if ((CHECK_HANDLE(handle)) || !config)
+               return CS_BAD_HANDLE;
+       s = SOCKET(handle);
+       if (!s)
+               return CS_BAD_HANDLE;
+       return pccard_get_configuration_info(s, handle->Function, config);
+}
+EXPORT_SYMBOL(pcmcia_get_configuration_info);
+
+
+/** pcmcia_get_window
+ */
+int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *handle,
+                     int idx, win_req_t *req)
+{
+       window_t *win;
+       int w;
+
+       if (!s || !(s->state & SOCKET_PRESENT))
+               return CS_NO_CARD;
+       for (w = idx; w < MAX_WIN; w++)
+               if (s->state & SOCKET_WIN_REQ(w))
+                       break;
+       if (w == MAX_WIN)
+               return CS_NO_MORE_ITEMS;
+       win = &s->win[w];
+       req->Base = win->ctl.res->start;
+       req->Size = win->ctl.res->end - win->ctl.res->start + 1;
+       req->AccessSpeed = win->ctl.speed;
+       req->Attributes = 0;
+       if (win->ctl.flags & MAP_ATTRIB)
+               req->Attributes |= WIN_MEMORY_TYPE_AM;
+       if (win->ctl.flags & MAP_ACTIVE)
+               req->Attributes |= WIN_ENABLE;
+       if (win->ctl.flags & MAP_16BIT)
+               req->Attributes |= WIN_DATA_WIDTH_16;
+       if (win->ctl.flags & MAP_USE_WAIT)
+               req->Attributes |= WIN_USE_WAIT;
+       *handle = win;
+       return CS_SUCCESS;
+} /* pcmcia_get_window */
+EXPORT_SYMBOL(pcmcia_get_window);
+
+
+/** pccard_get_status
+ *
+ * Get the current socket state bits.  We don't support the latched
+ * SocketState yet: I haven't seen any point for it.
+ */
+
+int pccard_get_status(struct pcmcia_socket *s, unsigned int function,
+                     cs_status_t *status)
+{
+       config_t *c;
+       int val;
+
+       s->ops->get_status(s, &val);
+       status->CardState = status->SocketState = 0;
+       status->CardState |= (val & SS_DETECT) ? CS_EVENT_CARD_DETECT : 0;
+       status->CardState |= (val & SS_CARDBUS) ? CS_EVENT_CB_DETECT : 0;
+       status->CardState |= (val & SS_3VCARD) ? CS_EVENT_3VCARD : 0;
+       status->CardState |= (val & SS_XVCARD) ? CS_EVENT_XVCARD : 0;
+       if (s->state & SOCKET_SUSPEND)
+               status->CardState |= CS_EVENT_PM_SUSPEND;
+       if (!(s->state & SOCKET_PRESENT))
+               return CS_NO_CARD;
+
+       c = (s->config != NULL) ? &s->config[function] : NULL;
+       if ((c != NULL) && (c->state & CONFIG_LOCKED) &&
+           (c->IntType & (INT_MEMORY_AND_IO | INT_ZOOMED_VIDEO))) {
+               u_char reg;
+               if (c->Present & PRESENT_PIN_REPLACE) {
+                       pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, &reg);
+                       status->CardState |=
+                               (reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0;
+                       status->CardState |=
+                               (reg & PRR_READY_STATUS) ? CS_EVENT_READY_CHANGE : 0;
+                       status->CardState |=
+                               (reg & PRR_BVD2_STATUS) ? CS_EVENT_BATTERY_LOW : 0;
+                       status->CardState |=
+                               (reg & PRR_BVD1_STATUS) ? CS_EVENT_BATTERY_DEAD : 0;
+               } else {
+                       /* No PRR?  Then assume we're always ready */
+                       status->CardState |= CS_EVENT_READY_CHANGE;
+               }
+               if (c->Present & PRESENT_EXT_STATUS) {
+                       pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, &reg);
+                       status->CardState |=
+                               (reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0;
+               }
+               return CS_SUCCESS;
+       }
+       status->CardState |=
+               (val & SS_WRPROT) ? CS_EVENT_WRITE_PROTECT : 0;
+       status->CardState |=
+               (val & SS_BATDEAD) ? CS_EVENT_BATTERY_DEAD : 0;
+       status->CardState |=
+               (val & SS_BATWARN) ? CS_EVENT_BATTERY_LOW : 0;
+       status->CardState |=
+               (val & SS_READY) ? CS_EVENT_READY_CHANGE : 0;
+       return CS_SUCCESS;
+} /* pccard_get_status */
+
+int pcmcia_get_status(client_handle_t handle, cs_status_t *status)
+{
+       struct pcmcia_socket *s;
+       if (CHECK_HANDLE(handle))
+               return CS_BAD_HANDLE;
+       s = SOCKET(handle);
+       return pccard_get_status(s, handle->Function, status);
+}
+EXPORT_SYMBOL(pcmcia_get_status);
+
+
+
+/** pcmcia_get_mem_page
+ *
+ * Change the card address of an already open memory window.
+ */
+int pcmcia_get_mem_page(window_handle_t win, memreq_t *req)
+{
+       if ((win == NULL) || (win->magic != WINDOW_MAGIC))
+               return CS_BAD_HANDLE;
+       req->Page = 0;
+       req->CardOffset = win->ctl.card_start;
+       return CS_SUCCESS;
+} /* pcmcia_get_mem_page */
+EXPORT_SYMBOL(pcmcia_get_mem_page);
+
+
+int pcmcia_map_mem_page(window_handle_t win, memreq_t *req)
+{
+       struct pcmcia_socket *s;
+       if ((win == NULL) || (win->magic != WINDOW_MAGIC))
+               return CS_BAD_HANDLE;
+       if (req->Page != 0)
+               return CS_BAD_PAGE;
+       s = win->sock;
+       win->ctl.card_start = req->CardOffset;
+       if (s->ops->set_mem_map(s, &win->ctl) != 0)
+               return CS_BAD_OFFSET;
+       return CS_SUCCESS;
+} /* pcmcia_map_mem_page */
+EXPORT_SYMBOL(pcmcia_map_mem_page);
+
+
+/** pcmcia_modify_configuration
+ *
+ * Modify a locked socket configuration
+ */
+int pcmcia_modify_configuration(client_handle_t handle,
+                               modconf_t *mod)
+{
+       struct pcmcia_socket *s;
+       config_t *c;
+
+       if (CHECK_HANDLE(handle))
+               return CS_BAD_HANDLE;
+       s = SOCKET(handle);
+       c = CONFIG(handle);
+       if (!(s->state & SOCKET_PRESENT))
+               return CS_NO_CARD;
+       if (!(c->state & CONFIG_LOCKED))
+               return CS_CONFIGURATION_LOCKED;
+
+       if (mod->Attributes & CONF_IRQ_CHANGE_VALID) {
+               if (mod->Attributes & CONF_ENABLE_IRQ) {
+                       c->Attributes |= CONF_ENABLE_IRQ;
+                       s->socket.io_irq = s->irq.AssignedIRQ;
+               } else {
+                       c->Attributes &= ~CONF_ENABLE_IRQ;
+                       s->socket.io_irq = 0;
+               }
+               s->ops->set_socket(s, &s->socket);
+       }
+
+       if (mod->Attributes & CONF_VCC_CHANGE_VALID)
+               return CS_BAD_VCC;
+
+       /* We only allow changing Vpp1 and Vpp2 to the same value */
+       if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) &&
+           (mod->Attributes & CONF_VPP2_CHANGE_VALID)) {
+               if (mod->Vpp1 != mod->Vpp2)
+                       return CS_BAD_VPP;
+               c->Vpp1 = c->Vpp2 = s->socket.Vpp = mod->Vpp1;
+               if (s->ops->set_socket(s, &s->socket))
+                       return CS_BAD_VPP;
+       } else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) ||
+                  (mod->Attributes & CONF_VPP2_CHANGE_VALID))
+               return CS_BAD_VPP;
+
+       return CS_SUCCESS;
+} /* modify_configuration */
+EXPORT_SYMBOL(pcmcia_modify_configuration);
+
+
+int pcmcia_release_configuration(client_handle_t handle)
+{
+       pccard_io_map io = { 0, 0, 0, 0, 1 };
+       struct pcmcia_socket *s;
+       int i;
+
+       if (CHECK_HANDLE(handle) ||
+           !(handle->state & CLIENT_CONFIG_LOCKED))
+               return CS_BAD_HANDLE;
+       handle->state &= ~CLIENT_CONFIG_LOCKED;
+       s = SOCKET(handle);
+
+#ifdef CONFIG_CARDBUS
+       if (handle->state & CLIENT_CARDBUS)
+               return CS_SUCCESS;
+#endif
+
+       if (!(handle->state & CLIENT_STALE)) {
+               config_t *c = CONFIG(handle);
+               if (--(s->lock_count) == 0) {
+                       s->socket.flags = SS_OUTPUT_ENA;   /* Is this correct? */
+                       s->socket.Vpp = 0;
+                       s->socket.io_irq = 0;
+                       s->ops->set_socket(s, &s->socket);
+               }
+               if (c->state & CONFIG_IO_REQ)
+                       for (i = 0; i < MAX_IO_WIN; i++) {
+                               if (s->io[i].NumPorts == 0)
+                                       continue;
+                               s->io[i].Config--;
+                               if (s->io[i].Config != 0)
+                                       continue;
+                               io.map = i;
+                               s->ops->set_io_map(s, &io);
+                       }
+               c->state &= ~CONFIG_LOCKED;
+       }
+
+       return CS_SUCCESS;
+} /* pcmcia_release_configuration */
+EXPORT_SYMBOL(pcmcia_release_configuration);
+
+
+/** pcmcia_release_io
+ *
+ * Release_io() releases the I/O ranges allocated by a client.  This
+ * may be invoked some time after a card ejection has already dumped
+ * the actual socket configuration, so if the client is "stale", we
+ * don't bother checking the port ranges against the current socket
+ * values.
+ */
+int pcmcia_release_io(client_handle_t handle, io_req_t *req)
+{
+       struct pcmcia_socket *s;
+
+       if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IO_REQ))
+               return CS_BAD_HANDLE;
+       handle->state &= ~CLIENT_IO_REQ;
+       s = SOCKET(handle);
+
+#ifdef CONFIG_CARDBUS
+       if (handle->state & CLIENT_CARDBUS)
+               return CS_SUCCESS;
+#endif
+
+       if (!(handle->state & CLIENT_STALE)) {
+               config_t *c = CONFIG(handle);
+               if (c->state & CONFIG_LOCKED)
+                       return CS_CONFIGURATION_LOCKED;
+               if ((c->io.BasePort1 != req->BasePort1) ||
+                   (c->io.NumPorts1 != req->NumPorts1) ||
+                   (c->io.BasePort2 != req->BasePort2) ||
+                   (c->io.NumPorts2 != req->NumPorts2))
+                       return CS_BAD_ARGS;
+               c->state &= ~CONFIG_IO_REQ;
+       }
+
+       release_io_space(s, req->BasePort1, req->NumPorts1);
+       if (req->NumPorts2)
+               release_io_space(s, req->BasePort2, req->NumPorts2);
+
+       return CS_SUCCESS;
+} /* pcmcia_release_io */
+EXPORT_SYMBOL(pcmcia_release_io);
+
+
+int pcmcia_release_irq(client_handle_t handle, irq_req_t *req)
+{
+       struct pcmcia_socket *s;
+       if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IRQ_REQ))
+               return CS_BAD_HANDLE;
+       handle->state &= ~CLIENT_IRQ_REQ;
+       s = SOCKET(handle);
+
+       if (!(handle->state & CLIENT_STALE)) {
+               config_t *c = CONFIG(handle);
+               if (c->state & CONFIG_LOCKED)
+                       return CS_CONFIGURATION_LOCKED;
+               if (c->irq.Attributes != req->Attributes)
+                       return CS_BAD_ATTRIBUTE;
+               if (s->irq.AssignedIRQ != req->AssignedIRQ)
+                       return CS_BAD_IRQ;
+               if (--s->irq.Config == 0) {
+                       c->state &= ~CONFIG_IRQ_REQ;
+                       s->irq.AssignedIRQ = 0;
+               }
+       }
+
+       if (req->Attributes & IRQ_HANDLE_PRESENT) {
+               free_irq(req->AssignedIRQ, req->Instance);
+       }
+
+#ifdef CONFIG_PCMCIA_PROBE
+       pcmcia_used_irq[req->AssignedIRQ]--;
+#endif
+
+       return CS_SUCCESS;
+} /* pcmcia_release_irq */
+EXPORT_SYMBOL(pcmcia_release_irq);
+
+
+int pcmcia_release_window(window_handle_t win)
+{
+       struct pcmcia_socket *s;
+
+       if ((win == NULL) || (win->magic != WINDOW_MAGIC))
+               return CS_BAD_HANDLE;
+       s = win->sock;
+       if (!(win->handle->state & CLIENT_WIN_REQ(win->index)))
+               return CS_BAD_HANDLE;
+
+       /* Shut down memory window */
+       win->ctl.flags &= ~MAP_ACTIVE;
+       s->ops->set_mem_map(s, &win->ctl);
+       s->state &= ~SOCKET_WIN_REQ(win->index);
+
+       /* Release system memory */
+       if (win->ctl.res) {
+               release_resource(win->ctl.res);
+               kfree(win->ctl.res);
+               win->ctl.res = NULL;
+       }
+       win->handle->state &= ~CLIENT_WIN_REQ(win->index);
+
+       win->magic = 0;
+
+       return CS_SUCCESS;
+} /* pcmcia_release_window */
+EXPORT_SYMBOL(pcmcia_release_window);
+
+
+int pcmcia_request_configuration(client_handle_t handle,
+                                config_req_t *req)
+{
+       int i;
+       u_int base;
+       struct pcmcia_socket *s;
+       config_t *c;
+       pccard_io_map iomap;
+
+       if (CHECK_HANDLE(handle))
+               return CS_BAD_HANDLE;
+       s = SOCKET(handle);
+       if (!(s->state & SOCKET_PRESENT))
+               return CS_NO_CARD;
+
+#ifdef CONFIG_CARDBUS
+       if (handle->state & CLIENT_CARDBUS)
+               return CS_UNSUPPORTED_MODE;
+#endif
+
+       if (req->IntType & INT_CARDBUS)
+               return CS_UNSUPPORTED_MODE;
+       c = CONFIG(handle);
+       if (c->state & CONFIG_LOCKED)
+               return CS_CONFIGURATION_LOCKED;
+
+       /* Do power control.  We don't allow changes in Vcc. */
+       if (s->socket.Vcc != req->Vcc)
+               return CS_BAD_VCC;
+       if (req->Vpp1 != req->Vpp2)
+               return CS_BAD_VPP;
+       s->socket.Vpp = req->Vpp1;
+       if (s->ops->set_socket(s, &s->socket))
+               return CS_BAD_VPP;
+
+       c->Vcc = req->Vcc; c->Vpp1 = c->Vpp2 = req->Vpp1;
+
+       /* Pick memory or I/O card, DMA mode, interrupt */
+       c->IntType = req->IntType;
+       c->Attributes = req->Attributes;
+       if (req->IntType & INT_MEMORY_AND_IO)
+               s->socket.flags |= SS_IOCARD;
+       if (req->IntType & INT_ZOOMED_VIDEO)
+               s->socket.flags |= SS_ZVCARD | SS_IOCARD;
+       if (req->Attributes & CONF_ENABLE_DMA)
+               s->socket.flags |= SS_DMA_MODE;
+       if (req->Attributes & CONF_ENABLE_SPKR)
+               s->socket.flags |= SS_SPKR_ENA;
+       if (req->Attributes & CONF_ENABLE_IRQ)
+               s->socket.io_irq = s->irq.AssignedIRQ;
+       else
+               s->socket.io_irq = 0;
+       s->ops->set_socket(s, &s->socket);
+       s->lock_count++;
+
+       /* Set up CIS configuration registers */
+       base = c->ConfigBase = req->ConfigBase;
+       c->Present = c->CardValues = req->Present;
+       if (req->Present & PRESENT_COPY) {
+               c->Copy = req->Copy;
+               pcmcia_write_cis_mem(s, 1, (base + CISREG_SCR)>>1, 1, &c->Copy);
+       }
+       if (req->Present & PRESENT_OPTION) {
+               if (s->functions == 1) {
+                       c->Option = req->ConfigIndex & COR_CONFIG_MASK;
+               } else {
+                       c->Option = req->ConfigIndex & COR_MFC_CONFIG_MASK;
+                       c->Option |= COR_FUNC_ENA|COR_IREQ_ENA;
+                       if (req->Present & PRESENT_IOBASE_0)
+                               c->Option |= COR_ADDR_DECODE;
+               }
+               if (c->state & CONFIG_IRQ_REQ)
+                       if (!(c->irq.Attributes & IRQ_FORCED_PULSE))
+                               c->Option |= COR_LEVEL_REQ;
+               pcmcia_write_cis_mem(s, 1, (base + CISREG_COR)>>1, 1, &c->Option);
+               mdelay(40);
+       }
+       if (req->Present & PRESENT_STATUS) {
+               c->Status = req->Status;
+               pcmcia_write_cis_mem(s, 1, (base + CISREG_CCSR)>>1, 1, &c->Status);
+       }
+       if (req->Present & PRESENT_PIN_REPLACE) {
+               c->Pin = req->Pin;
+               pcmcia_write_cis_mem(s, 1, (base + CISREG_PRR)>>1, 1, &c->Pin);
+       }
+       if (req->Present & PRESENT_EXT_STATUS) {
+               c->ExtStatus = req->ExtStatus;
+               pcmcia_write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1, &c->ExtStatus);
+       }
+       if (req->Present & PRESENT_IOBASE_0) {
+               u_char b = c->io.BasePort1 & 0xff;
+               pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &b);
+               b = (c->io.BasePort1 >> 8) & 0xff;
+               pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_1)>>1, 1, &b);
+       }
+       if (req->Present & PRESENT_IOSIZE) {
+               u_char b = c->io.NumPorts1 + c->io.NumPorts2 - 1;
+               pcmcia_write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &b);
+       }
+
+       /* Configure I/O windows */
+       if (c->state & CONFIG_IO_REQ) {
+               iomap.speed = io_speed;
+               for (i = 0; i < MAX_IO_WIN; i++)
+                       if (s->io[i].NumPorts != 0) {
+                               iomap.map = i;
+                               iomap.flags = MAP_ACTIVE;
+                               switch (s->io[i].Attributes & IO_DATA_PATH_WIDTH) {
+                               case IO_DATA_PATH_WIDTH_16:
+                                       iomap.flags |= MAP_16BIT; break;
+                               case IO_DATA_PATH_WIDTH_AUTO:
+                                       iomap.flags |= MAP_AUTOSZ; break;
+                               default:
+                                       break;
+                               }
+                               iomap.start = s->io[i].BasePort;
+                               iomap.stop = iomap.start + s->io[i].NumPorts - 1;
+                               s->ops->set_io_map(s, &iomap);
+                               s->io[i].Config++;
+                       }
+       }
+
+       c->state |= CONFIG_LOCKED;
+       handle->state |= CLIENT_CONFIG_LOCKED;
+       return CS_SUCCESS;
+} /* pcmcia_request_configuration */
+EXPORT_SYMBOL(pcmcia_request_configuration);
+
+
+/** pcmcia_request_io
+ *
+ * Request_io() reserves ranges of port addresses for a socket.
+ * I have not implemented range sharing or alias addressing.
+ */
+int pcmcia_request_io(client_handle_t handle, io_req_t *req)
+{
+       struct pcmcia_socket *s;
+       config_t *c;
+
+       if (CHECK_HANDLE(handle))
+               return CS_BAD_HANDLE;
+       s = SOCKET(handle);
+       if (!(s->state & SOCKET_PRESENT))
+               return CS_NO_CARD;
+
+       if (handle->state & CLIENT_CARDBUS) {
+#ifdef CONFIG_CARDBUS
+               handle->state |= CLIENT_IO_REQ;
+               return CS_SUCCESS;
+#else
+               return CS_UNSUPPORTED_FUNCTION;
+#endif
+       }
+
+       if (!req)
+               return CS_UNSUPPORTED_MODE;
+       c = CONFIG(handle);
+       if (c->state & CONFIG_LOCKED)
+               return CS_CONFIGURATION_LOCKED;
+       if (c->state & CONFIG_IO_REQ)
+               return CS_IN_USE;
+       if (req->Attributes1 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS))
+               return CS_BAD_ATTRIBUTE;
+       if ((req->NumPorts2 > 0) &&
+           (req->Attributes2 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS)))
+               return CS_BAD_ATTRIBUTE;
+
+       if (alloc_io_space(s, req->Attributes1, &req->BasePort1,
+                          req->NumPorts1, req->IOAddrLines))
+               return CS_IN_USE;
+
+       if (req->NumPorts2) {
+               if (alloc_io_space(s, req->Attributes2, &req->BasePort2,
+                                  req->NumPorts2, req->IOAddrLines)) {
+                       release_io_space(s, req->BasePort1, req->NumPorts1);
+                       return CS_IN_USE;
+               }
+       }
+
+       c->io = *req;
+       c->state |= CONFIG_IO_REQ;
+       handle->state |= CLIENT_IO_REQ;
+       return CS_SUCCESS;
+} /* pcmcia_request_io */
+EXPORT_SYMBOL(pcmcia_request_io);
+
+
+/** pcmcia_request_irq
+ *
+ * Request_irq() reserves an irq for this client.
+ *
+ * Also, since Linux only reserves irq's when they are actually
+ * hooked, we don't guarantee that an irq will still be available
+ * when the configuration is locked.  Now that I think about it,
+ * there might be a way to fix this using a dummy handler.
+ */
+
+#ifdef CONFIG_PCMCIA_PROBE
+static irqreturn_t test_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+       return IRQ_NONE;
+}
+#endif
+
+int pcmcia_request_irq(client_handle_t handle, irq_req_t *req)
+{
+       struct pcmcia_socket *s;
+       config_t *c;
+       int ret = CS_IN_USE, irq = 0;
+       struct pcmcia_device *p_dev = handle_to_pdev(handle);
+
+       if (CHECK_HANDLE(handle))
+               return CS_BAD_HANDLE;
+       s = SOCKET(handle);
+       if (!(s->state & SOCKET_PRESENT))
+               return CS_NO_CARD;
+       c = CONFIG(handle);
+       if (c->state & CONFIG_LOCKED)
+               return CS_CONFIGURATION_LOCKED;
+       if (c->state & CONFIG_IRQ_REQ)
+               return CS_IN_USE;
+
+#ifdef CONFIG_PCMCIA_PROBE
+       if (s->irq.AssignedIRQ != 0) {
+               /* If the interrupt is already assigned, it must be the same */
+               irq = s->irq.AssignedIRQ;
+       } else {
+               int try;
+               u32 mask = s->irq_mask;
+               void *data = NULL;
+
+               for (try = 0; try < 64; try++) {
+                       irq = try % 32;
+
+                       /* marked as available by driver, and not blocked by userspace? */
+                       if (!((mask >> irq) & 1))
+                               continue;
+
+                       /* avoid an IRQ which is already used by a PCMCIA card */
+                       if ((try < 32) && pcmcia_used_irq[irq])
+                               continue;
+
+                       /* register the correct driver, if possible, of check whether
+                        * registering a dummy handle works, i.e. if the IRQ isn't
+                        * marked as used by the kernel resource management core */
+                       ret = request_irq(irq,
+                                         (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Handler : test_action,
+                                         ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) ||
+                                          (s->functions > 1) ||
+                                          (irq == s->pci_irq)) ? SA_SHIRQ : 0,
+                                         p_dev->dev.bus_id,
+                                         (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Instance : data);
+                       if (!ret) {
+                               if (!(req->Attributes & IRQ_HANDLE_PRESENT))
+                                       free_irq(irq, data);
+                               break;
+                       }
+               }
+       }
+#endif
+       if (ret) {
+               if (!s->pci_irq)
+                       return ret;
+               irq = s->pci_irq;
+       }
+
+       if (ret && req->Attributes & IRQ_HANDLE_PRESENT) {
+               if (request_irq(irq, req->Handler,
+                               ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) ||
+                                (s->functions > 1) ||
+                                (irq == s->pci_irq)) ? SA_SHIRQ : 0,
+                               p_dev->dev.bus_id, req->Instance))
+                       return CS_IN_USE;
+       }
+
+       c->irq.Attributes = req->Attributes;
+       s->irq.AssignedIRQ = req->AssignedIRQ = irq;
+       s->irq.Config++;
+
+       c->state |= CONFIG_IRQ_REQ;
+       handle->state |= CLIENT_IRQ_REQ;
+
+#ifdef CONFIG_PCMCIA_PROBE
+       pcmcia_used_irq[irq]++;
+#endif
+
+       return CS_SUCCESS;
+} /* pcmcia_request_irq */
+EXPORT_SYMBOL(pcmcia_request_irq);
+
+
+/** pcmcia_request_window
+ *
+ * Request_window() establishes a mapping between card memory space
+ * and system memory space.
+ */
+int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle_t *wh)
+{
+       struct pcmcia_socket *s;
+       window_t *win;
+       u_long align;
+       int w;
+
+       if (CHECK_HANDLE(*handle))
+               return CS_BAD_HANDLE;
+       s = (*handle)->Socket;
+       if (!(s->state & SOCKET_PRESENT))
+               return CS_NO_CARD;
+       if (req->Attributes & (WIN_PAGED | WIN_SHARED))
+               return CS_BAD_ATTRIBUTE;
+
+       /* Window size defaults to smallest available */
+       if (req->Size == 0)
+               req->Size = s->map_size;
+       align = (((s->features & SS_CAP_MEM_ALIGN) ||
+                 (req->Attributes & WIN_STRICT_ALIGN)) ?
+                req->Size : s->map_size);
+       if (req->Size & (s->map_size-1))
+               return CS_BAD_SIZE;
+       if ((req->Base && (s->features & SS_CAP_STATIC_MAP)) ||
+           (req->Base & (align-1)))
+               return CS_BAD_BASE;
+       if (req->Base)
+               align = 0;
+
+       /* Allocate system memory window */
+       for (w = 0; w < MAX_WIN; w++)
+               if (!(s->state & SOCKET_WIN_REQ(w))) break;
+       if (w == MAX_WIN)
+               return CS_OUT_OF_RESOURCE;
+
+       win = &s->win[w];
+       win->magic = WINDOW_MAGIC;
+       win->index = w;
+       win->handle = *handle;
+       win->sock = s;
+
+       if (!(s->features & SS_CAP_STATIC_MAP)) {
+               win->ctl.res = pcmcia_find_mem_region(req->Base, req->Size, align,
+                                                     (req->Attributes & WIN_MAP_BELOW_1MB), s);
+               if (!win->ctl.res)
+                       return CS_IN_USE;
+       }
+       (*handle)->state |= CLIENT_WIN_REQ(w);
+
+       /* Configure the socket controller */
+       win->ctl.map = w+1;
+       win->ctl.flags = 0;
+       win->ctl.speed = req->AccessSpeed;
+       if (req->Attributes & WIN_MEMORY_TYPE)
+               win->ctl.flags |= MAP_ATTRIB;
+       if (req->Attributes & WIN_ENABLE)
+               win->ctl.flags |= MAP_ACTIVE;
+       if (req->Attributes & WIN_DATA_WIDTH_16)
+               win->ctl.flags |= MAP_16BIT;
+       if (req->Attributes & WIN_USE_WAIT)
+               win->ctl.flags |= MAP_USE_WAIT;
+       win->ctl.card_start = 0;
+       if (s->ops->set_mem_map(s, &win->ctl) != 0)
+               return CS_BAD_ARGS;
+       s->state |= SOCKET_WIN_REQ(w);
+
+       /* Return window handle */
+       if (s->features & SS_CAP_STATIC_MAP) {
+               req->Base = win->ctl.static_start;
+       } else {
+               req->Base = win->ctl.res->start;
+       }
+       *wh = win;
+
+       return CS_SUCCESS;
+} /* pcmcia_request_window */
+EXPORT_SYMBOL(pcmcia_request_window);
index b6843f8..0668384 100644 (file)
@@ -72,7 +72,7 @@ int pcmcia_adjust_resource_info(adjust_t *adj)
                        /* you can't use the old interface if the new
                         * one was used before */
                        spin_lock_irqsave(&s->lock, flags);
-                       if ((s->resource_setup_done) &&
+                       if ((s->resource_setup_new) &&
                            !(s->resource_setup_old)) {
                                spin_unlock_irqrestore(&s->lock, flags);
                                continue;
@@ -105,29 +105,32 @@ void pcmcia_validate_mem(struct pcmcia_socket *s)
 }
 EXPORT_SYMBOL(pcmcia_validate_mem);
 
-int adjust_io_region(struct resource *res, unsigned long r_start,
+int pcmcia_adjust_io_region(struct resource *res, unsigned long r_start,
                     unsigned long r_end, struct pcmcia_socket *s)
 {
        if (s->resource_ops->adjust_io_region)
                return s->resource_ops->adjust_io_region(res, r_start, r_end, s);
        return -ENOMEM;
 }
+EXPORT_SYMBOL(pcmcia_adjust_io_region);
 
-struct resource *find_io_region(unsigned long base, int num,
+struct resource *pcmcia_find_io_region(unsigned long base, int num,
                   unsigned long align, struct pcmcia_socket *s)
 {
        if (s->resource_ops->find_io)
                return s->resource_ops->find_io(base, num, align, s);
        return NULL;
 }
+EXPORT_SYMBOL(pcmcia_find_io_region);
 
-struct resource *find_mem_region(u_long base, u_long num, u_long align,
+struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align,
                                 int low, struct pcmcia_socket *s)
 {
        if (s->resource_ops->find_mem)
                return s->resource_ops->find_mem(base, num, align, low, s);
        return NULL;
 }
+EXPORT_SYMBOL(pcmcia_find_mem_region);
 
 void release_resource_db(struct pcmcia_socket *s)
 {
index 5876bab..c42455d 100644 (file)
@@ -372,6 +372,9 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s)
           base, base+num-1);
     bad = fail = 0;
     step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
+    /* don't allow too large steps */
+    if (step > 0x800000)
+       step = 0x800000;
     /* cis_readable wants to map 2x map_size */
     if (step < 2 * s->map_size)
        step = 2 * s->map_size;
@@ -465,8 +468,7 @@ static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
 
        for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
                mm = *m;
-               if (do_mem_probe(mm.base, mm.num, s))
-                       break;
+               do_mem_probe(mm.base, mm.num, s);
        }
 }
 
@@ -601,7 +603,7 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star
 
 ======================================================================*/
 
-struct resource *nonstatic_find_io_region(unsigned long base, int num,
+static struct resource *nonstatic_find_io_region(unsigned long base, int num,
                   unsigned long align, struct pcmcia_socket *s)
 {
        struct resource *res = make_resource(0, num, IORESOURCE_IO, s->dev.class_id);
@@ -635,8 +637,8 @@ struct resource *nonstatic_find_io_region(unsigned long base, int num,
        return res;
 }
 
-struct resource * nonstatic_find_mem_region(u_long base, u_long num, u_long align,
-                                int low, struct pcmcia_socket *s)
+static struct resource * nonstatic_find_mem_region(u_long base, u_long num,
+               u_long align, int low, struct pcmcia_socket *s)
 {
        struct resource *res = make_resource(0, num, IORESOURCE_MEM, s->dev.class_id);
        struct socket_data *s_data = s->resource_data;
@@ -683,27 +685,23 @@ struct resource * nonstatic_find_mem_region(u_long base, u_long num, u_long alig
 }
 
 
-static int adjust_memory(struct pcmcia_socket *s, adjust_t *adj)
+static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
 {
-       u_long base, num;
        struct socket_data *data = s->resource_data;
-       int ret;
-
-       base = adj->resource.memory.Base;
-       num = adj->resource.memory.Size;
-       if ((num == 0) || (base+num-1 < base))
-               return CS_BAD_SIZE;
+       unsigned long size = end - start + 1;
+       int ret = 0;
 
-       ret = CS_SUCCESS;
+       if (end <= start)
+               return -EINVAL;
 
        down(&rsrc_sem);
-       switch (adj->Action) {
+       switch (action) {
        case ADD_MANAGED_RESOURCE:
-               ret = add_interval(&data->mem_db, base, num);
+               ret = add_interval(&data->mem_db, start, size);
                break;
        case REMOVE_MANAGED_RESOURCE:
-               ret = sub_interval(&data->mem_db, base, num);
-               if (ret == CS_SUCCESS) {
+               ret = sub_interval(&data->mem_db, start, size);
+               if (!ret) {
                        struct pcmcia_socket *socket;
                        down_read(&pcmcia_socket_list_rwsem);
                        list_for_each_entry(socket, &pcmcia_socket_list, socket_list)
@@ -712,7 +710,7 @@ static int adjust_memory(struct pcmcia_socket *s, adjust_t *adj)
                }
                break;
        default:
-               ret = CS_UNSUPPORTED_FUNCTION;
+               ret = -EINVAL;
        }
        up(&rsrc_sem);
 
@@ -720,36 +718,35 @@ static int adjust_memory(struct pcmcia_socket *s, adjust_t *adj)
 }
 
 
-static int adjust_io(struct pcmcia_socket *s, adjust_t *adj)
+static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
 {
        struct socket_data *data = s->resource_data;
-       kio_addr_t base, num;
-       int ret = CS_SUCCESS;
+       unsigned long size = end - start + 1;
+       int ret = 0;
 
-       base = adj->resource.io.BasePort;
-       num = adj->resource.io.NumPorts;
-       if ((base < 0) || (base > 0xffff))
-               return CS_BAD_BASE;
-       if ((num <= 0) || (base+num > 0x10000) || (base+num <= base))
-               return CS_BAD_SIZE;
+       if (end <= start)
+               return -EINVAL;
+
+       if (end > IO_SPACE_LIMIT)
+               return -EINVAL;
 
        down(&rsrc_sem);
-       switch (adj->Action) {
+       switch (action) {
        case ADD_MANAGED_RESOURCE:
-               if (add_interval(&data->io_db, base, num) != 0) {
-                       ret = CS_IN_USE;
+               if (add_interval(&data->io_db, start, size) != 0) {
+                       ret = -EBUSY;
                        break;
                }
 #ifdef CONFIG_PCMCIA_PROBE
                if (probe_io)
-                       do_io_probe(s, base, num);
+                       do_io_probe(s, start, size);
 #endif
                break;
        case REMOVE_MANAGED_RESOURCE:
-               sub_interval(&data->io_db, base, num);
+               sub_interval(&data->io_db, start, size);
                break;
        default:
-               ret = CS_UNSUPPORTED_FUNCTION;
+               ret = -EINVAL;
                break;
        }
        up(&rsrc_sem);
@@ -760,15 +757,82 @@ static int adjust_io(struct pcmcia_socket *s, adjust_t *adj)
 
 static int nonstatic_adjust_resource_info(struct pcmcia_socket *s, adjust_t *adj)
 {
+       unsigned long end;
+
        switch (adj->Resource) {
        case RES_MEMORY_RANGE:
-               return adjust_memory(s, adj);
+               end = adj->resource.memory.Base + adj->resource.memory.Size - 1;
+               return adjust_memory(s, adj->Action, adj->resource.memory.Base, end);
        case RES_IO_RANGE:
-               return adjust_io(s, adj);
+               end = adj->resource.io.BasePort + adj->resource.io.NumPorts - 1;
+               return adjust_io(s, adj->Action, adj->resource.io.BasePort, end);
        }
        return CS_UNSUPPORTED_FUNCTION;
 }
 
+#ifdef CONFIG_PCI
+static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
+{
+       struct resource *res;
+       int i, done = 0;
+
+       if (!s->cb_dev || !s->cb_dev->bus)
+               return -ENODEV;
+
+#if defined(CONFIG_X86) || defined(CONFIG_X86_64)
+       /* If this is the root bus, the risk of hitting
+        * some strange system devices which aren't protected
+        * by either ACPI resource tables or properly requested
+        * resources is too big. Therefore, don't do auto-adding
+        * of resources at the moment.
+        */
+       if (s->cb_dev->bus->number == 0)
+               return -EINVAL;
+#endif
+
+       for (i=0; i < PCI_BUS_NUM_RESOURCES; i++) {
+               res = s->cb_dev->bus->resource[i];
+               if (!res)
+                       continue;
+
+               if (res->flags & IORESOURCE_IO) {
+                       if (res == &ioport_resource)
+                               continue;
+                       printk(KERN_INFO "pcmcia: parent PCI bridge I/O window: 0x%lx - 0x%lx\n",
+                              res->start, res->end);
+                       if (!adjust_io(s, ADD_MANAGED_RESOURCE, res->start, res->end))
+                               done |= IORESOURCE_IO;
+
+               }
+
+               if (res->flags & IORESOURCE_MEM) {
+                       if (res == &iomem_resource)
+                               continue;
+                       printk(KERN_INFO "pcmcia: parent PCI bridge Memory window: 0x%lx - 0x%lx\n",
+                              res->start, res->end);
+                       if (!adjust_memory(s, ADD_MANAGED_RESOURCE, res->start, res->end))
+                               done |= IORESOURCE_MEM;
+               }
+       }
+
+       /* if we got at least one of IO, and one of MEM, we can be glad and
+        * activate the PCMCIA subsystem */
+       if (done & (IORESOURCE_MEM | IORESOURCE_IO))
+               s->resource_setup_done = 1;
+
+       return 0;
+}
+
+#else
+
+static inline int nonstatic_autoadd_resources(struct pcmcia_socket *s)
+{
+       return -ENODEV;
+}
+
+#endif
+
+
 static int nonstatic_init(struct pcmcia_socket *s)
 {
        struct socket_data *data;
@@ -783,6 +847,8 @@ static int nonstatic_init(struct pcmcia_socket *s)
 
        s->resource_data = (void *) data;
 
+       nonstatic_autoadd_resources(s);
+
        return 0;
 }
 
@@ -845,17 +911,16 @@ static ssize_t store_io_db(struct class_device *class_dev, const char *buf, size
 {
        struct pcmcia_socket *s = class_get_devdata(class_dev);
        unsigned long start_addr, end_addr;
-       unsigned int add = 1;
-       adjust_t adj;
+       unsigned int add = ADD_MANAGED_RESOURCE;
        ssize_t ret = 0;
 
        ret = sscanf (buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
        if (ret != 2) {
                ret = sscanf (buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
-               add = 0;
+               add = REMOVE_MANAGED_RESOURCE;
                if (ret != 2) {
                        ret = sscanf (buf, "0x%lx - 0x%lx", &start_addr, &end_addr);
-                       add = 1;
+                       add = ADD_MANAGED_RESOURCE;
                        if (ret != 2)
                                return -EINVAL;
                }
@@ -863,12 +928,9 @@ static ssize_t store_io_db(struct class_device *class_dev, const char *buf, size
        if (end_addr <= start_addr)
                return -EINVAL;
 
-       adj.Action = add ? ADD_MANAGED_RESOURCE : REMOVE_MANAGED_RESOURCE;
-       adj.Resource = RES_IO_RANGE;
-       adj.resource.io.BasePort = start_addr;
-       adj.resource.io.NumPorts = end_addr - start_addr + 1;
-
-       ret = adjust_io(s, &adj);
+       ret = adjust_io(s, add, start_addr, end_addr);
+       if (!ret)
+               s->resource_setup_new = 1;
 
        return ret ? ret : count;
 }
@@ -901,17 +963,16 @@ static ssize_t store_mem_db(struct class_device *class_dev, const char *buf, siz
 {
        struct pcmcia_socket *s = class_get_devdata(class_dev);
        unsigned long start_addr, end_addr;
-       unsigned int add = 1;
-       adjust_t adj;
+       unsigned int add = ADD_MANAGED_RESOURCE;
        ssize_t ret = 0;
 
        ret = sscanf (buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
        if (ret != 2) {
                ret = sscanf (buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
-               add = 0;
+               add = REMOVE_MANAGED_RESOURCE;
                if (ret != 2) {
                        ret = sscanf (buf, "0x%lx - 0x%lx", &start_addr, &end_addr);
-                       add = 1;
+                       add = ADD_MANAGED_RESOURCE;
                        if (ret != 2)
                                return -EINVAL;
                }
@@ -919,12 +980,9 @@ static ssize_t store_mem_db(struct class_device *class_dev, const char *buf, siz
        if (end_addr <= start_addr)
                return -EINVAL;
 
-       adj.Action = add ? ADD_MANAGED_RESOURCE : REMOVE_MANAGED_RESOURCE;
-       adj.Resource = RES_MEMORY_RANGE;
-       adj.resource.memory.Base = start_addr;
-       adj.resource.memory.Size = end_addr - start_addr + 1;
-
-       ret = adjust_memory(s, &adj);
+       ret = adjust_memory(s, add, start_addr, end_addr);
+       if (!ret)
+               s->resource_setup_new = 1;
 
        return ret ? ret : count;
 }
index 8eed039..fcef54c 100644 (file)
@@ -163,28 +163,164 @@ static ssize_t pccard_store_resource(struct class_device *dev, const char *buf,
                return -EINVAL;
 
        spin_lock_irqsave(&s->lock, flags);
-       if (!s->resource_setup_done) {
+       if (!s->resource_setup_done)
                s->resource_setup_done = 1;
-               spin_unlock_irqrestore(&s->lock, flags);
+       spin_unlock_irqrestore(&s->lock, flags);
+
+       down(&s->skt_sem);
+       if ((s->callback) &&
+           (s->state & SOCKET_PRESENT) &&
+           !(s->state & SOCKET_CARDBUS)) {
+               if (try_module_get(s->callback->owner)) {
+                       s->callback->requery(s);
+                       module_put(s->callback->owner);
+               }
+       }
+       up(&s->skt_sem);
+
+       return count;
+}
+static CLASS_DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource);
+
+
+static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf, loff_t off, size_t count)
+{
+       tuple_t tuple;
+       int status, i;
+       loff_t pointer = 0;
+       ssize_t ret = 0;
+       u_char *tuplebuffer;
+       u_char *tempbuffer;
+
+       tuplebuffer = kmalloc(sizeof(u_char) * 256, GFP_KERNEL);
+       if (!tuplebuffer)
+               return -ENOMEM;
+
+       tempbuffer = kmalloc(sizeof(u_char) * 258, GFP_KERNEL);
+       if (!tempbuffer) {
+               ret = -ENOMEM;
+               goto free_tuple;
+       }
+
+       memset(&tuple, 0, sizeof(tuple_t));
+
+       tuple.Attributes = TUPLE_RETURN_LINK | TUPLE_RETURN_COMMON;
+       tuple.DesiredTuple = RETURN_FIRST_TUPLE;
+       tuple.TupleOffset = 0;
+
+       status = pccard_get_first_tuple(s, BIND_FN_ALL, &tuple);
+       while (!status) {
+               tuple.TupleData = tuplebuffer;
+               tuple.TupleDataMax = 255;
+               memset(tuplebuffer, 0, sizeof(u_char) * 255);
 
+               status = pccard_get_tuple_data(s, &tuple);
+               if (status)
+                       break;
+
+               if (off < (pointer + 2 + tuple.TupleDataLen)) {
+                       tempbuffer[0] = tuple.TupleCode & 0xff;
+                       tempbuffer[1] = tuple.TupleLink & 0xff;
+                       for (i = 0; i < tuple.TupleDataLen; i++)
+                               tempbuffer[i + 2] = tuplebuffer[i] & 0xff;
+
+                       for (i = 0; i < (2 + tuple.TupleDataLen); i++) {
+                               if (((i + pointer) >= off) &&
+                                   (i + pointer) < (off + count)) {
+                                       buf[ret] = tempbuffer[i];
+                                       ret++;
+                               }
+                       }
+               }
+
+               pointer += 2 + tuple.TupleDataLen;
+
+               if (pointer >= (off + count))
+                       break;
+
+               if (tuple.TupleCode == CISTPL_END)
+                       break;
+               status = pccard_get_next_tuple(s, BIND_FN_ALL, &tuple);
+       }
+
+       kfree(tempbuffer);
+ free_tuple:
+       kfree(tuplebuffer);
+
+       return (ret);
+}
+
+static ssize_t pccard_show_cis(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+       unsigned int size = 0x200;
+
+       if (off >= size)
+               count = 0;
+       else {
+               struct pcmcia_socket *s;
+               cisinfo_t cisinfo;
+
+               if (off + count > size)
+                       count = size - off;
+
+               s = to_socket(container_of(kobj, struct class_device, kobj));
+
+               if (!(s->state & SOCKET_PRESENT))
+                       return -ENODEV;
+               if (pccard_validate_cis(s, BIND_FN_ALL, &cisinfo))
+                       return -EIO;
+               if (!cisinfo.Chains)
+                       return -ENODATA;
+
+               count = pccard_extract_cis(s, buf, off, count);
+       }
+
+       return (count);
+}
+
+static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+       struct pcmcia_socket *s = to_socket(container_of(kobj, struct class_device, kobj));
+       cisdump_t *cis;
+       ssize_t ret = count;
+
+       if (off)
+               return -EINVAL;
+
+       if (count >= 0x200)
+               return -EINVAL;
+
+       if (!(s->state & SOCKET_PRESENT))
+               return -ENODEV;
+
+       cis = kmalloc(sizeof(cisdump_t), GFP_KERNEL);
+       if (!cis)
+               return -ENOMEM;
+       memset(cis, 0, sizeof(cisdump_t));
+
+       cis->Length = count + 1;
+       memcpy(cis->Data, buf, count);
+
+       if (pcmcia_replace_cis(s, cis))
+               ret  = -EIO;
+
+       kfree(cis);
+
+       if (!ret) {
                down(&s->skt_sem);
-               if ((s->callback) &&
-                   (s->state & SOCKET_PRESENT) &&
+               if ((s->callback) && (s->state & SOCKET_PRESENT) &&
                    !(s->state & SOCKET_CARDBUS)) {
                        if (try_module_get(s->callback->owner)) {
-                               s->callback->resources_done(s);
+                               s->callback->requery(s);
                                module_put(s->callback->owner);
                        }
                }
                up(&s->skt_sem);
-
-               return count;
        }
-       spin_unlock_irqrestore(&s->lock, flags);
 
-       return count;
+
+       return (ret);
 }
-static CLASS_DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource);
 
 
 static struct class_device_attribute *pccard_socket_attributes[] = {
@@ -199,6 +335,13 @@ static struct class_device_attribute *pccard_socket_attributes[] = {
        NULL,
 };
 
+static struct bin_attribute pccard_cis_attr = {
+       .attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR, .owner = THIS_MODULE},
+       .size = 0x200,
+       .read = pccard_show_cis,
+       .write = pccard_store_cis,
+};
+
 static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev)
 {
        struct class_device_attribute **attr;
@@ -209,6 +352,8 @@ static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev)
                if (ret)
                        break;
        }
+       if (!ret)
+               ret = sysfs_create_bin_file(&class_dev->kobj, &pccard_cis_attr);
 
        return ret;
 }
@@ -217,6 +362,7 @@ static void __devexit pccard_sysfs_remove_socket(struct class_device *class_dev)
 {
        struct class_device_attribute **attr;
 
+       sysfs_remove_bin_file(&class_dev->kobj, &pccard_cis_attr);
        for (attr = pccard_socket_attributes; *attr; attr++)
                class_device_remove_file(class_dev, *attr);
 }
index bee0536..02b23ab 100644 (file)
@@ -549,6 +549,11 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ
        unsigned offset;
        unsigned mask;
 
+       res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr;
+       /* Already allocated? */
+       if (res->parent)
+               return 0;
+
        /* The granularity of the memory limit is 4kB, on IO it's 4 bytes */
        mask = ~0xfff;
        if (type & IORESOURCE_IO)
@@ -556,7 +561,6 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ
 
        offset = 0x1c + 8*nr;
        bus = socket->dev->subordinate;
-       res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr;
        res->name = bus->name;
        res->flags = type;
        res->start = 0;
index e60b4c0..f1f6bf5 100644 (file)
@@ -318,6 +318,16 @@ static int aha152x_event(event_t event, int priority,
     return 0;
 }
 
+static struct pcmcia_device_id aha152x_ids[] = {
+       PCMCIA_DEVICE_PROD_ID123("New Media", "SCSI", "Bus Toaster", 0xcdf7e4cc, 0x35f26476, 0xa8851d6e),
+       PCMCIA_DEVICE_PROD_ID123("NOTEWORTHY", "SCSI", "Bus Toaster", 0xad89c6e8, 0x35f26476, 0xa8851d6e),
+       PCMCIA_DEVICE_PROD_ID12("Adaptec, Inc.", "APA-1460 SCSI Host Adapter", 0x24ba9738, 0x3a3c3d20),
+       PCMCIA_DEVICE_PROD_ID12("New Media Corporation", "Multimedia Sound/SCSI", 0x085a850b, 0x80a6535c),
+       PCMCIA_DEVICE_PROD_ID12("NOTEWORTHY", "NWCOMB02 SCSI/AUDIO COMBO CARD", 0xad89c6e8, 0x5f9a615b),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, aha152x_ids);
+
 static struct pcmcia_driver aha152x_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -325,6 +335,7 @@ static struct pcmcia_driver aha152x_cs_driver = {
        },
        .attach         = aha152x_attach,
        .detach         = aha152x_detach,
+       .id_table       = aha152x_ids,
 };
 
 static int __init init_aha152x_cs(void)
index 3df7bc7..853e6ee 100644 (file)
@@ -299,6 +299,15 @@ static int fdomain_event(event_t event, int priority,
     return 0;
 } /* fdomain_event */
 
+
+static struct pcmcia_device_id fdomain_ids[] = {
+       PCMCIA_DEVICE_PROD_ID12("IBM Corp.", "SCSI PCMCIA Card", 0xe3736c88, 0x859cad20),
+       PCMCIA_DEVICE_PROD_ID1("SCSI PCMCIA Adapter Card", 0x8dacb57e),
+       PCMCIA_DEVICE_PROD_ID12(" SIMPLE TECHNOLOGY Corporation", "SCSI PCMCIA Credit Card Controller", 0x182bdafe, 0xc80d106f),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, fdomain_ids);
+
 static struct pcmcia_driver fdomain_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -306,6 +315,7 @@ static struct pcmcia_driver fdomain_cs_driver = {
        },
        .attach         = fdomain_attach,
        .detach         = fdomain_detach,
+       .id_table       = fdomain_ids,
 };
 
 static int __init init_fdomain_cs(void)
index 3dddb32..91b3f28 100644 (file)
@@ -2125,6 +2125,18 @@ static int nsp_cs_event(event_t                 event,
  *     module entry point
  *====================================================================*/
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68))
+static struct pcmcia_device_id nsp_cs_ids[] = {
+       PCMCIA_DEVICE_PROD_ID123("IO DATA", "CBSC16       ", "1", 0x547e66dc, 0x0d63a3fd, 0x51de003a),
+       PCMCIA_DEVICE_PROD_ID123("KME    ", "SCSI-CARD-001", "1", 0x534c02bc, 0x52008408, 0x51de003a),
+       PCMCIA_DEVICE_PROD_ID123("KME    ", "SCSI-CARD-002", "1", 0x534c02bc, 0xcb09d5b2, 0x51de003a),
+       PCMCIA_DEVICE_PROD_ID123("KME    ", "SCSI-CARD-003", "1", 0x534c02bc, 0xbc0ee524, 0x51de003a),
+       PCMCIA_DEVICE_PROD_ID123("KME    ", "SCSI-CARD-004", "1", 0x534c02bc, 0x226a7087, 0x51de003a),
+       PCMCIA_DEVICE_PROD_ID123("WBT", "NinjaSCSI-3", "R1.0", 0xc7ba805f, 0xfdc7c97d, 0x6973710e),
+       PCMCIA_DEVICE_PROD_ID123("WORKBIT", "UltraNinja-16", "1", 0x28191418, 0xb70f4b09, 0x51de003a),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, nsp_cs_ids);
+
 static struct pcmcia_driver nsp_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -2132,6 +2144,7 @@ static struct pcmcia_driver nsp_driver = {
        },
        .attach         = nsp_cs_attach,
        .detach         = nsp_cs_detach,
+       .id_table       = nsp_cs_ids,
 };
 #endif
 
index a0175f5..0dcf411 100644 (file)
@@ -395,6 +395,27 @@ static int qlogic_event(event_t event, int priority, event_callback_args_t * arg
        return 0;
 }                              /* qlogic_event */
 
+static struct pcmcia_device_id qlogic_ids[] = {
+       PCMCIA_DEVICE_PROD_ID12("EIger Labs", "PCMCIA-to-SCSI Adapter", 0x88395fa7, 0x33b7a5e6),
+       PCMCIA_DEVICE_PROD_ID12("EPSON", "SCSI-2 PC Card SC200", 0xd361772f, 0x299d1751),
+       PCMCIA_DEVICE_PROD_ID12("MACNICA", "MIRACLE SCSI-II mPS110", 0x20841b68, 0xab3c3b6d),
+       PCMCIA_DEVICE_PROD_ID12("MIDORI ELECTRONICS ", "CN-SC43", 0x6534382a, 0xd67eee79),
+       PCMCIA_DEVICE_PROD_ID12("NEC", "PC-9801N-J03R", 0x18df0ba0, 0x24662e8a),
+       PCMCIA_DEVICE_PROD_ID12("KME ", "KXLC003", 0x82375a27, 0xf68e5bf7),
+       PCMCIA_DEVICE_PROD_ID12("KME ", "KXLC004", 0x82375a27, 0x68eace54),
+       PCMCIA_DEVICE_PROD_ID12("KME", "KXLC101", 0x3faee676, 0x194250ec),
+       PCMCIA_DEVICE_PROD_ID12("QLOGIC CORPORATION", "pc05", 0xd77b2930, 0xa85b2735),
+       PCMCIA_DEVICE_PROD_ID12("QLOGIC CORPORATION", "pc05 rev 1.10", 0xd77b2930, 0x70f8b5f8),
+       PCMCIA_DEVICE_PROD_ID123("KME", "KXLC002", "00", 0x3faee676, 0x81896b61, 0xf99f065f),
+       PCMCIA_DEVICE_PROD_ID12("RATOC System Inc.", "SCSI2 CARD 37", 0x85c10e17, 0x1a2640c1),
+       PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "SCSC200A PC CARD SCSI", 0xb4585a1a, 0xa6f06ebe),
+       PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "SCSC200B PC CARD SCSI-10", 0xb4585a1a, 0x0a88dea0),
+       /* these conflict with other cards! */
+       /* PCMCIA_DEVICE_PROD_ID123("MACNICA", "MIRACLE SCSI", "mPS100", 0x20841b68, 0xf8dedaeb, 0x89f7fafb), */
+       /* PCMCIA_DEVICE_PROD_ID123("MACNICA", "MIRACLE SCSI", "mPS100", 0x20841b68, 0xf8dedaeb, 0x89f7fafb), */
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, qlogic_ids);
 
 static struct pcmcia_driver qlogic_cs_driver = {
        .owner          = THIS_MODULE,
@@ -403,6 +424,7 @@ static struct pcmcia_driver qlogic_cs_driver = {
        },
        .attach         = qlogic_attach,
        .detach         = qlogic_detach,
+       .id_table       = qlogic_ids,
 };
 
 static int __init init_qlogic_cs(void)
index 1667da9..7d4b16b 100644 (file)
@@ -999,6 +999,14 @@ MODULE_AUTHOR("Bob Tracy <rct@frus.com>");
 MODULE_DESCRIPTION("SYM53C500 PCMCIA SCSI driver");
 MODULE_LICENSE("GPL");
 
+static struct pcmcia_device_id sym53c500_ids[] = {
+       PCMCIA_DEVICE_PROD_ID12("BASICS by New Media Corporation", "SCSI Sym53C500", 0x23c78a9d, 0x0099e7f7),
+       PCMCIA_DEVICE_PROD_ID12("New Media Corporation", "SCSI Bus Toaster Sym53C500", 0x085a850b, 0x45432eb8),
+       PCMCIA_DEVICE_PROD_ID2("SCSI9000", 0x21648f44),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, sym53c500_ids);
+
 static struct pcmcia_driver sym53c500_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -1006,6 +1014,7 @@ static struct pcmcia_driver sym53c500_cs_driver = {
        },
        .attach         = SYM53C500_attach,
        .detach         = SYM53C500_detach,
+       .id_table       = sym53c500_ids,
 };
 
 static int __init
index 0d7b65f..73a34b1 100644 (file)
@@ -772,6 +772,111 @@ serial_event(event_t event, int priority, event_callback_args_t * args)
        return 0;
 }
 
+static struct pcmcia_device_id serial_ids[] = {
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0057, 0x0021),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0089, 0x110a),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0104, 0x000a),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0xea15),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0109, 0x0501),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0138, 0x110a),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0140, 0x000a),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0143, 0x3341),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0143, 0xc0ab),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x016c, 0x0081),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x021b, 0x0101),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x08a1, 0xc0ab),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0d0a),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0e0a),
+       PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63),
+       PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63),
+       PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0xf510db04, 0x856d66c8, 0xbd6c43ef),
+       PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "XJEM1144/CCEM1144", "PCMCIA MODEM", 0xf510db04, 0x52d21e1e, 0xbd6c43ef),
+       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM28", 0x2e3ee845, 0x0ea978ea),
+       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM33", 0x2e3ee845, 0x80609023),
+       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM56", 0x2e3ee845, 0xa650c32a),
+       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "REM10", 0x2e3ee845, 0x76df1d29),
+       PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "XEM5600", 0x2e3ee845, 0xf1403719),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "AnyCom", "Fast Ethernet ", 0x578ba6e7, 0x02d92d1e),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "D-Link", "DME336T", 0x1a424a1c, 0xb23897ff),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Grey Cell", "GCS3000", 0x2a151fac, 0x48b932ae),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Linksys", "EtherFast 10&100 + 56K PC Card (PCMLM56)", 0x0733cc81, 0xb3765033),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard", 0x0c2f80cd, 0x0573c29f),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard", 0x0c2f80cd, 0x0573c29f),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "LanModem", 0xdcfe12d3, 0xc67c648f),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "TDK", "GlobalNetworker 3410/3412", 0x1eae9475, 0xd9a93bed),
+       PCMCIA_PFC_DEVICE_PROD_ID12(1, "Xircom", "CreditCard Ethernet", 0x2e3ee845, 0xc0e778c2),
+       PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0104, 0x0070),
+       PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0101, 0x0562),
+       PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0104, 0x0070),
+       PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x016c, 0x0020),
+       PCMCIA_MFC_DEVICE_PROD_ID123(1, "APEX DATA", "MULTICARD", "ETHERNET-MODEM", 0x11c2da09, 0x7289dc5d, 0xaad95e1f),
+       PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "Home and Away 28.8 PC Card       ", 0xb569a6e5, 0x5bd4ff2c),
+       PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "Home and Away Credit Card Adapter", 0xb569a6e5, 0x4bdf15c3),
+       PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "w95 Home and Away Credit Card ", 0xb569a6e5, 0xae911c15),
+       PCMCIA_MFC_DEVICE_PROD_ID1(1, "Motorola MARQUIS", 0xf03e4e77),
+       PCMCIA_MFC_DEVICE_PROD_ID2(1, "FAX/Modem/Ethernet Combo Card ", 0x1ed59302),
+       PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0301),
+       PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0039),
+       PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0006),
+       PCMCIA_DEVICE_MANF_CARD(0x0105, 0x410a),
+       PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d50),
+       PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d51),
+       PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d52),
+       PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d53),
+       PCMCIA_DEVICE_MANF_CARD(0x010b, 0xd180),
+       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x000e),
+       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x001b),
+       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0025),
+       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0045),
+       PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0052),
+       PCMCIA_DEVICE_PROD_ID134("ADV", "TECH", "COMpad-32/85", 0x67459937, 0x916d02ba, 0x8fbe92ae),
+       PCMCIA_DEVICE_PROD_ID124("GATEWAY2000", "CC3144", "PCMCIA MODEM", 0x506bccae, 0xcb3685f1, 0xbd6c43ef),
+       PCMCIA_DEVICE_PROD_ID14("MEGAHERTZ", "PCMCIA MODEM", 0xf510db04, 0xbd6c43ef),
+       PCMCIA_DEVICE_PROD_ID124("TOSHIBA", "T144PF", "PCMCIA MODEM", 0xb4585a1a, 0x7271409c, 0xbd6c43ef),
+       PCMCIA_DEVICE_PROD_ID123("FUJITSU", "FC14F ", "MBH10213", 0x6ee5a3d8, 0x30ead12b, 0xb00f05a0),
+       PCMCIA_DEVICE_PROD_ID13("MEGAHERTZ", "V.34 PCMCIA MODEM", 0xf510db04, 0xbb2cce4a),
+       PCMCIA_DEVICE_PROD_ID12("Brain Boxes", "Bluetooth PC Card", 0xee138382, 0xd4ce9b02),
+       PCMCIA_DEVICE_PROD_ID12("CIRRUS LOGIC", "FAX MODEM", 0xe625f451, 0xcecd6dfa),
+       PCMCIA_DEVICE_PROD_ID12("COMPAQ", "PCMCIA 28800 FAX/DATA MODEM", 0xa3a3062c, 0x8cbd7c76),
+       PCMCIA_DEVICE_PROD_ID12("COMPAQ", "PCMCIA 33600 FAX/DATA MODEM", 0xa3a3062c, 0x5a00ce95),
+       PCMCIA_DEVICE_PROD_ID12("Computerboards, Inc.", "PCM-COM422", 0xd0b78f51, 0x7e2d49ed),
+       PCMCIA_DEVICE_PROD_ID12("Dr. Neuhaus", "FURY CARD 14K4", 0x76942813, 0x8b96ce65),
+       PCMCIA_DEVICE_PROD_ID12("Intelligent", "ANGIA FAX/MODEM", 0xb496e65e, 0xf31602a6),
+       PCMCIA_DEVICE_PROD_ID12("Intel", "MODEM 2400", 0x816cc815, 0x23539b80),
+       PCMCIA_DEVICE_PROD_ID12("IOTech Inc ", "PCMCIA Dual RS-232 Serial Port Card", 0x3bd2d898, 0x92abc92f),
+       PCMCIA_DEVICE_PROD_ID12("MACRONIX", "FAX/MODEM", 0x668388b3, 0x3f9bdf2f),
+       PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT1432LT", 0x5f73be51, 0x0b3e2383),
+       PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT2834LT", 0x5f73be51, 0x4cd7c09e),
+       PCMCIA_DEVICE_PROD_ID12("OEM      ", "C288MX     ", 0xb572d360, 0xd2385b7a),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA   ", "C336MX     ", 0x99bcafe9, 0xaa25bcab),
+       PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "PCMCIA Dual RS-232 Serial Port Card", 0xc4420b35, 0x92abc92f),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "EN2218-LAN/MODEM", 0x281f1c5d, 0x570f348e, "PCMLM28.cis"),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "UE2218-LAN/MODEM", 0x281f1c5d, 0x6fdcacee, "PCMLM28.cis"),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet", 0xf5f025c2, 0x338e8155, "PCMLM28.cis"),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet GSM", 0xf5f025c2, 0x4ae85d35, "PCMLM28.cis"),
+       PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "LINKSYS", "PCMLM28", 0xf7cb0b07, 0x66881874, "PCMLM28.cis"),
+       PCMCIA_MFC_DEVICE_CIS_PROD_ID12(1, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "DP83903.cis"),
+       PCMCIA_MFC_DEVICE_CIS_PROD_ID4(1, "NSC MF LAN/Modem", 0x58fc6056, "DP83903.cis"),
+       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0556, "3CCFEM556.cis"),
+       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0175, 0x0000, "DP83903.cis"),
+       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0035, "3CXEM556.cis"),
+       PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x003d, "3CXEM556.cis"),
+       PCMCIA_DEVICE_CIS_PROD_ID12("MultiTech", "PCMCIA 56K DataFax", 0x842047ee, 0xc2efcf03, "MT5634ZLX.cis"),
+       PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-4", 0x96913a85, 0xcec8f102, "COMpad4.cis"),
+       PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "COMpad2.cis"),
+       PCMCIA_DEVICE_CIS_PROD_ID2("RS-COM 2P", 0xad20b156, "RS-COM-2P.cis"),
+       /* too generic */
+       /* PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0160, 0x0002), */
+       /* PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0160, 0x0002), */
+       PCMCIA_DEVICE_FUNC_ID(2),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, serial_ids);
+
 static struct pcmcia_driver serial_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -779,6 +884,7 @@ static struct pcmcia_driver serial_cs_driver = {
        },
        .attach         = serial_attach,
        .detach         = serial_detach,
+       .id_table       = serial_ids,
 };
 
 static int __init init_serial_cs(void)
index e1ef0d7..ce5ebfe 100644 (file)
@@ -295,6 +295,12 @@ static int ixj_event(event_t event, int priority, event_callback_args_t * args)
        return 0;
 }
 
+static struct pcmcia_device_id ixj_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(0x0257, 0x0600),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, ixj_ids);
+
 static struct pcmcia_driver ixj_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -302,6 +308,7 @@ static struct pcmcia_driver ixj_driver = {
        },
        .attach         = ixj_attach,
        .detach         = ixj_detach,
+       .id_table       = ixj_ids,
 };
 
 static int __init ixj_pcmcia_init(void)
index 6e17326..269d8ef 100644 (file)
@@ -68,13 +68,6 @@ static const char driver_name[DEV_NAME_LEN]  = "sl811_cs";
 
 static dev_link_t *dev_list = NULL;
 
-static int irq_list[4] = { -1 };
-static int irq_list_count;
-
-module_param_array(irq_list, int, &irq_list_count, 0444);
-
-INT_MODULE_PARM(irq_mask, 0xdeb8);
-
 typedef struct local_info_t {
        dev_link_t              link;
        dev_node_t              node;
@@ -373,7 +366,7 @@ static dev_link_t *sl811_cs_attach(void)
        local_info_t *local;
        dev_link_t *link;
        client_reg_t client_reg;
-       int ret, i;
+       int ret;
 
        local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
        if (!local)
@@ -385,11 +378,6 @@ static dev_link_t *sl811_cs_attach(void)
        /* Initialize */
        link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
        link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
-       if (irq_list[0] == -1)
-               link->irq.IRQInfo2 = irq_mask;
-       else
-               for (i = 0; i < irq_list_count; i++)
-                       link->irq.IRQInfo2 |= 1 << irq_list[i];
        link->irq.Handler = NULL;
 
        link->conf.Attributes = 0;
@@ -418,6 +406,12 @@ static dev_link_t *sl811_cs_attach(void)
        return link;
 }
 
+static struct pcmcia_device_id sl811_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(0xc015, 0x0001), /* RATOC USB HOST CF+ Card */
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, sl811_ids);
+
 static struct pcmcia_driver sl811_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
@@ -425,6 +419,7 @@ static struct pcmcia_driver sl811_cs_driver = {
        },
        .attach         = sl811_cs_attach,
        .detach         = sl811_cs_detach,
+       .id_table       = sl811_ids,
 };
 
 /*====================================================================*/
index 859ebf4..79dfab8 100644 (file)
@@ -41,13 +41,17 @@ static __inline__ int ide_default_irq(unsigned long base)
 
 static __inline__ unsigned long ide_default_io_base(int index)
 {
+       if (pci_find_device(PCI_ANY_ID, PCI_ANY_ID, NULL) == NULL) {
+               switch(index) {
+                       case 2: return 0x1e8;
+                       case 3: return 0x168;
+                       case 4: return 0x1e0;
+                       case 5: return 0x160;
+               }
+       }
        switch (index) {
                case 0: return 0x1f0;
                case 1: return 0x170;
-               case 2: return 0x1e8;
-               case 3: return 0x168;
-               case 4: return 0x1e0;
-               case 5: return 0x160;
                default:
                        return 0;
        }
index 5eb01dd..81a590a 100644 (file)
@@ -75,6 +75,8 @@
 
 #ifndef __ASSEMBLY__
 
+extern void __iomem *auxio_register;
+
 #define AUXIO_LTE_ON   1
 #define AUXIO_LTE_OFF  0
 
index e071b4b..49d49a2 100644 (file)
@@ -159,7 +159,7 @@ static void sun_82077_fd_outb(unsigned char value, unsigned long port)
  * underruns.  If non-zero, doing_pdma encodes the direction of
  * the transfer for debugging.  1=read 2=write
  */
-char *pdma_vaddr;
+unsigned char *pdma_vaddr;
 unsigned long pdma_size;
 volatile int doing_pdma = 0;
 
@@ -209,8 +209,7 @@ static void sun_fd_enable_dma(void)
        pdma_areasize = pdma_size;
 }
 
-/* Our low-level entry point in arch/sparc/kernel/entry.S */
-extern irqreturn_t floppy_hardint(int irq, void *unused, struct pt_regs *regs);
+extern irqreturn_t sparc_floppy_irq(int, void *, struct pt_regs *);
 
 static int sun_fd_request_irq(void)
 {
@@ -220,8 +219,8 @@ static int sun_fd_request_irq(void)
        if(!once) {
                once = 1;
 
-               error = request_fast_irq(FLOPPY_IRQ, floppy_hardint
-                                        SA_INTERRUPT, "floppy", NULL);
+               error = request_irq(FLOPPY_IRQ, sparc_floppy_irq
+                                   SA_INTERRUPT, "floppy", NULL);
 
                return ((error == 0) ? 0 : -1);
        }
@@ -615,7 +614,7 @@ static unsigned long __init sun_floppy_init(void)
                struct linux_ebus *ebus;
                struct linux_ebus_device *edev = NULL;
                unsigned long config = 0;
-               unsigned long auxio_reg;
+               void __iomem *auxio_reg;
 
                for_each_ebus(ebus) {
                        for_each_ebusdev(edev, ebus) {
@@ -642,7 +641,7 @@ static unsigned long __init sun_floppy_init(void)
                /* Make sure the high density bit is set, some systems
                 * (most notably Ultra5/Ultra10) come up with it clear.
                 */
-               auxio_reg = edev->resource[2].start;
+               auxio_reg = (void __iomem *) edev->resource[2].start;
                writel(readl(auxio_reg)|0x2, auxio_reg);
 
                sun_pci_ebus_dev = ebus->self;
@@ -650,7 +649,8 @@ static unsigned long __init sun_floppy_init(void)
                spin_lock_init(&sun_pci_fd_ebus_dma.lock);
 
                /* XXX ioremap */
-               sun_pci_fd_ebus_dma.regs = edev->resource[1].start;
+               sun_pci_fd_ebus_dma.regs = (void __iomem *)
+                       edev->resource[1].start;
                if (!sun_pci_fd_ebus_dma.regs)
                        return 0;
 
index 3aef0ca..018e2e4 100644 (file)
@@ -19,7 +19,7 @@
 /* You should not mess with this directly. That's the job of irq.c.
  *
  * If you make changes here, please update hand coded assembler of
- * SBUS/floppy interrupt handler in entry.S -DaveM
+ * the vectored interrupt trap handler in entry.S -DaveM
  *
  * This is currently one DCACHE line, two buckets per L2 cache
  * line.  Keep this in mind please.
@@ -122,11 +122,6 @@ extern void enable_irq(unsigned int);
 extern unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long imap);
 extern unsigned int sbus_build_irq(void *sbus, unsigned int ino);
 
-extern int request_fast_irq(unsigned int irq,
-                           irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                           unsigned long flags, __const__ char *devname,
-                           void *dev_id);
-
 static __inline__ void set_softint(unsigned long bits)
 {
        __asm__ __volatile__("wr        %0, 0x0, %%set_softint"
index bf2ae90..a1cc94f 100644 (file)
@@ -55,8 +55,9 @@ static __inline__ int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
                "add            %%g1, %1, %%g7\n\t"
                "cas            [%2], %%g1, %%g7\n\t"
                "cmp            %%g1, %%g7\n\t"
+               "membar         #StoreLoad | #StoreStore\n\t"
                "bne,pn         %%icc, 1b\n\t"
-               " membar        #StoreLoad | #StoreStore\n\t"
+               " nop\n\t"
                "mov            %%g7, %0\n\t"
                : "=&r" (tmp)
                : "0" (tmp), "r" (sem)
index db7581b..9cb93a5 100644 (file)
@@ -52,12 +52,14 @@ static inline void _raw_spin_lock(spinlock_t *lock)
 
        __asm__ __volatile__(
 "1:    ldstub          [%1], %0\n"
+"      membar          #StoreLoad | #StoreStore\n"
 "      brnz,pn         %0, 2f\n"
-"       membar         #StoreLoad | #StoreStore\n"
+"       nop\n"
 "      .subsection     2\n"
 "2:    ldub            [%1], %0\n"
+"      membar          #LoadLoad\n"
 "      brnz,pt         %0, 2b\n"
-"       membar         #LoadLoad\n"
+"       nop\n"
 "      ba,a,pt         %%xcc, 1b\n"
 "      .previous"
        : "=&r" (tmp)
@@ -95,16 +97,18 @@ static inline void _raw_spin_lock_flags(spinlock_t *lock, unsigned long flags)
 
        __asm__ __volatile__(
 "1:    ldstub          [%2], %0\n"
-"      brnz,pn         %0, 2f\n"
 "      membar          #StoreLoad | #StoreStore\n"
+"      brnz,pn         %0, 2f\n"
+"       nop\n"
 "      .subsection     2\n"
 "2:    rdpr            %%pil, %1\n"
 "      wrpr            %3, %%pil\n"
 "3:    ldub            [%2], %0\n"
-"      brnz,pt         %0, 3b\n"
 "      membar          #LoadLoad\n"
+"      brnz,pt         %0, 3b\n"
+"       nop\n"
 "      ba,pt           %%xcc, 1b\n"
-"      wrpr            %1, %%pil\n"
+"       wrpr           %1, %%pil\n"
 "      .previous"
        : "=&r" (tmp1), "=&r" (tmp2)
        : "r"(lock), "r"(flags)
@@ -162,12 +166,14 @@ static void inline __read_lock(rwlock_t *lock)
 "4:     add            %0, 1, %1\n"
 "      cas             [%2], %0, %1\n"
 "      cmp             %0, %1\n"
+"      membar          #StoreLoad | #StoreStore\n"
 "      bne,pn          %%icc, 1b\n"
-"       membar         #StoreLoad | #StoreStore\n"
+"       nop\n"
 "      .subsection     2\n"
 "2:    ldsw            [%2], %0\n"
+"      membar          #LoadLoad\n"
 "      brlz,pt         %0, 2b\n"
-"       membar         #LoadLoad\n"
+"       nop\n"
 "      ba,a,pt         %%xcc, 4b\n"
 "      .previous"
        : "=&r" (tmp1), "=&r" (tmp2)
@@ -204,12 +210,14 @@ static void inline __write_lock(rwlock_t *lock)
 "4:     or             %0, %3, %1\n"
 "      cas             [%2], %0, %1\n"
 "      cmp             %0, %1\n"
+"      membar          #StoreLoad | #StoreStore\n"
 "      bne,pn          %%icc, 1b\n"
-"       membar         #StoreLoad | #StoreStore\n"
+"       nop\n"
 "      .subsection     2\n"
 "2:    lduw            [%2], %0\n"
+"      membar          #LoadLoad\n"
 "      brnz,pt         %0, 2b\n"
-"       membar         #LoadLoad\n"
+"       nop\n"
 "      ba,a,pt         %%xcc, 4b\n"
 "      .previous"
        : "=&r" (tmp1), "=&r" (tmp2)
@@ -240,8 +248,9 @@ static int inline __write_trylock(rwlock_t *lock)
 "       or             %0, %4, %1\n"
 "      cas             [%3], %0, %1\n"
 "      cmp             %0, %1\n"
+"      membar          #StoreLoad | #StoreStore\n"
 "      bne,pn          %%icc, 1b\n"
-"       membar         #StoreLoad | #StoreStore\n"
+"       nop\n"
 "      mov             1, %2\n"
 "2:"
        : "=&r" (tmp1), "=&r" (tmp2), "=&r" (result)
index 9d7613e..1aa9327 100644 (file)
@@ -111,7 +111,6 @@ static __inline__ void spitfire_put_dcache_tag(unsigned long addr, unsigned long
                             "membar    #Sync"
                             : /* No outputs */
                             : "r" (tag), "r" (addr), "i" (ASI_DCACHE_TAG));
-       __asm__ __volatile__ ("membar #Sync" : : : "memory");
 }
 
 /* The instruction cache lines are flushed with this, but note that
index d6eb7b2..9b6d051 100644 (file)
@@ -175,4 +175,50 @@ struct serio_device_id {
 };
 
 
+/* PCMCIA */
+
+struct pcmcia_device_id {
+       __u16           match_flags;
+
+       __u16           manf_id;
+       __u16           card_id;
+
+       __u8            func_id;
+
+       /* for real multi-function devices */
+       __u8            function;
+
+       /* for pseude multi-function devices */
+       __u8            device_no;
+
+       __u32           prod_id_hash[4];
+
+       /* not matched against in kernelspace*/
+#ifdef __KERNEL__
+       const char *    prod_id[4];
+#else
+       kernel_ulong_t  prod_id[4];
+#endif
+
+       /* not matched against */
+       kernel_ulong_t  driver_info;
+#ifdef __KERNEL__
+       char *          cisfile;
+#else
+       kernel_ulong_t  cisfile;
+#endif
+};
+
+#define PCMCIA_DEV_ID_MATCH_MANF_ID    0x0001
+#define PCMCIA_DEV_ID_MATCH_CARD_ID    0x0002
+#define PCMCIA_DEV_ID_MATCH_FUNC_ID    0x0004
+#define PCMCIA_DEV_ID_MATCH_FUNCTION   0x0008
+#define PCMCIA_DEV_ID_MATCH_PROD_ID1   0x0010
+#define PCMCIA_DEV_ID_MATCH_PROD_ID2   0x0020
+#define PCMCIA_DEV_ID_MATCH_PROD_ID3   0x0040
+#define PCMCIA_DEV_ID_MATCH_PROD_ID4   0x0080
+#define PCMCIA_DEV_ID_MATCH_DEVICE_NO  0x0100
+#define PCMCIA_DEV_ID_MATCH_FAKE_CIS   0x0200
+#define PCMCIA_DEV_ID_MATCH_ANONYMOUS  0x0400
+
 #endif /* LINUX_MOD_DEVICETABLE_H */
index a3961e1..1e0bc6a 100644 (file)
 #define PCI_VENDOR_ID_ITE              0x1283
 #define PCI_DEVICE_ID_ITE_IT8172G      0x8172
 #define PCI_DEVICE_ID_ITE_IT8172G_AUDIO 0x0801
+#define PCI_DEVICE_ID_ITE_8211         0x8211
+#define PCI_DEVICE_ID_ITE_8212         0x8212
 #define PCI_DEVICE_ID_ITE_8872         0x8872
 #define PCI_DEVICE_ID_ITE_IT8330G_0    0xe886
 
index 2000b43..da19c29 100644 (file)
 
 #define MANFID_TDK                     0x0105
 #define PRODID_TDK_CF010               0x0900
+#define PRODID_TDK_NP9610              0x0d0a
+#define PRODID_TDK_MN3200              0x0e0a
 #define PRODID_TDK_GN3410              0x4815
 
 #define MANFID_TOSHIBA                 0x0098
index 8d8643a..b42ddc0 100644 (file)
@@ -396,7 +396,6 @@ struct pcmcia_socket;
 int pcmcia_access_configuration_register(client_handle_t handle, conf_reg_t *reg);
 int pcmcia_deregister_client(client_handle_t handle);
 int pcmcia_get_configuration_info(client_handle_t handle, config_info_t *config);
-int pcmcia_get_card_services_info(servinfo_t *info);
 int pcmcia_get_first_window(window_handle_t *win, win_req_t *req);
 int pcmcia_get_next_window(window_handle_t *win, win_req_t *req);
 int pcmcia_get_status(client_handle_t handle, cs_status_t *status);
@@ -417,7 +416,6 @@ int pcmcia_suspend_card(struct pcmcia_socket *skt);
 int pcmcia_resume_card(struct pcmcia_socket *skt);
 int pcmcia_eject_card(struct pcmcia_socket *skt);
 int pcmcia_insert_card(struct pcmcia_socket *skt);
-int pcmcia_report_error(client_handle_t handle, error_info_t *err);
 
 struct pcmcia_socket * pcmcia_get_socket(struct pcmcia_socket *skt);
 void pcmcia_put_socket(struct pcmcia_socket *skt);
diff --git a/include/pcmcia/device_id.h b/include/pcmcia/device_id.h
new file mode 100644 (file)
index 0000000..346d81e
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * Copyright (2003-2004)       Dominik Brodowski <linux@brodo.de>
+ *                             David Woodhouse
+ *
+ * License: GPL v2
+ */
+
+#define PCMCIA_DEVICE_MANF_CARD(manf, card) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_MANF_ID| \
+                       PCMCIA_DEV_ID_MATCH_CARD_ID, \
+       .manf_id = (manf), \
+       .card_id = (card), }
+
+#define PCMCIA_DEVICE_FUNC_ID(func) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_FUNC_ID, \
+       .func_id = (func), }
+
+#define PCMCIA_DEVICE_PROD_ID1(v1, vh1) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1, \
+       .prod_id = { (v1), NULL, NULL, NULL }, \
+       .prod_id_hash = { (vh1), 0, 0, 0 }, }
+
+#define PCMCIA_DEVICE_PROD_ID2(v2, vh2) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID2, \
+       .prod_id = { NULL, (v2), NULL, NULL },  \
+       .prod_id_hash = { 0, (vh2), 0, 0 }, }
+
+#define PCMCIA_DEVICE_PROD_ID12(v1, v2, vh1, vh2) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID2, \
+       .prod_id = { (v1), (v2), NULL, NULL }, \
+       .prod_id_hash = { (vh1), (vh2), 0, 0 }, }
+
+#define PCMCIA_DEVICE_PROD_ID13(v1, v3, vh1, vh3) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID3, \
+       .prod_id = { (v1), NULL, (v3), NULL }, \
+       .prod_id_hash = { (vh1), 0, (vh3), 0 }, }
+
+#define PCMCIA_DEVICE_PROD_ID14(v1, v4, vh1, vh4) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID4, \
+       .prod_id = { (v1), NULL, NULL, (v4) }, \
+       .prod_id_hash = { (vh1), 0, 0, (vh4) }, }
+
+#define PCMCIA_DEVICE_PROD_ID123(v1, v2, v3, vh1, vh2, vh3) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID3, \
+       .prod_id = { (v1), (v2), (v3), NULL },\
+       .prod_id_hash = { (vh1), (vh2), (vh3), 0 }, }
+
+#define PCMCIA_DEVICE_PROD_ID124(v1, v2, v4, vh1, vh2, vh4) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID4, \
+       .prod_id = { (v1), (v2), NULL, (v4) }, \
+       .prod_id_hash = { (vh1), (vh2), 0, (vh4) }, }
+
+#define PCMCIA_DEVICE_PROD_ID134(v1, v3, v4, vh1, vh3, vh4) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID3| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID4, \
+       .prod_id = { (v1), NULL, (v3), (v4) }, \
+       .prod_id_hash = { (vh1), 0, (vh3), (vh4) }, }
+
+#define PCMCIA_DEVICE_PROD_ID1234(v1, v2, v3, v4, vh1, vh2, vh3, vh4) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID3| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID4, \
+       .prod_id = { (v1), (v2), (v3), (v4) }, \
+       .prod_id_hash = { (vh1), (vh2), (vh3), (vh4) }, }
+
+
+/* multi-function devices */
+
+#define PCMCIA_MFC_DEVICE_MANF_CARD(mfc, manf, card) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_MANF_ID| \
+                       PCMCIA_DEV_ID_MATCH_CARD_ID| \
+                       PCMCIA_DEV_ID_MATCH_FUNCTION, \
+       .manf_id = (manf), \
+       .card_id = (card), \
+       .function = (mfc), }
+
+#define PCMCIA_MFC_DEVICE_PROD_ID1(mfc, v1, vh1) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_FUNCTION, \
+       .prod_id = { (v1), NULL, NULL, NULL }, \
+       .prod_id_hash = { (vh1), 0, 0, 0 }, \
+       .function = (mfc), }
+
+#define PCMCIA_MFC_DEVICE_PROD_ID2(mfc, v2, vh2) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+                       PCMCIA_DEV_ID_MATCH_FUNCTION, \
+       .prod_id = { NULL, (v2), NULL, NULL },  \
+       .prod_id_hash = { 0, (vh2), 0, 0 }, \
+       .function = (mfc), }
+
+#define PCMCIA_MFC_DEVICE_PROD_ID12(mfc, v1, v2, vh1, vh2) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+                       PCMCIA_DEV_ID_MATCH_FUNCTION, \
+       .prod_id = { (v1), (v2), NULL, NULL }, \
+       .prod_id_hash = { (vh1), (vh2), 0, 0 }, \
+       .function = (mfc), }
+
+#define PCMCIA_MFC_DEVICE_PROD_ID13(mfc, v1, v3, vh1, vh3) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID3| \
+                       PCMCIA_DEV_ID_MATCH_FUNCTION, \
+       .prod_id = { (v1), NULL, (v3), NULL }, \
+       .prod_id_hash = { (vh1), 0, (vh3), 0 }, \
+       .function = (mfc), }
+
+#define PCMCIA_MFC_DEVICE_PROD_ID123(mfc, v1, v2, v3, vh1, vh2, vh3) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID3| \
+                       PCMCIA_DEV_ID_MATCH_FUNCTION, \
+       .prod_id = { (v1), (v2), (v3), NULL },\
+       .prod_id_hash = { (vh1), (vh2), (vh3), 0 }, \
+       .function = (mfc), }
+
+/* pseudo multi-function devices */
+
+#define PCMCIA_PFC_DEVICE_MANF_CARD(mfc, manf, card) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_MANF_ID| \
+                       PCMCIA_DEV_ID_MATCH_CARD_ID| \
+                       PCMCIA_DEV_ID_MATCH_DEVICE_NO, \
+       .manf_id = (manf), \
+       .card_id = (card), \
+       .device_no = (mfc), }
+
+#define PCMCIA_PFC_DEVICE_PROD_ID1(mfc, v1, vh1) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_DEVICE_NO, \
+       .prod_id = { (v1), NULL, NULL, NULL }, \
+       .prod_id_hash = { (vh1), 0, 0, 0 }, \
+       .device_no = (mfc), }
+
+#define PCMCIA_PFC_DEVICE_PROD_ID2(mfc, v2, vh2) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+                       PCMCIA_DEV_ID_MATCH_DEVICE_NO, \
+       .prod_id = { NULL, (v2), NULL, NULL },  \
+       .prod_id_hash = { 0, (vh2), 0, 0 }, \
+       .device_no = (mfc), }
+
+#define PCMCIA_PFC_DEVICE_PROD_ID12(mfc, v1, v2, vh1, vh2) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+                       PCMCIA_DEV_ID_MATCH_DEVICE_NO, \
+       .prod_id = { (v1), (v2), NULL, NULL }, \
+       .prod_id_hash = { (vh1), (vh2), 0, 0 }, \
+       .device_no = (mfc), }
+
+#define PCMCIA_PFC_DEVICE_PROD_ID13(mfc, v1, v3, vh1, vh3) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID3| \
+                       PCMCIA_DEV_ID_MATCH_DEVICE_NO, \
+       .prod_id = { (v1), NULL, (v3), NULL }, \
+       .prod_id_hash = { (vh1), 0, (vh3), 0 }, \
+       .device_no = (mfc), }
+
+#define PCMCIA_PFC_DEVICE_PROD_ID123(mfc, v1, v2, v3, vh1, vh2, vh3) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID3| \
+                       PCMCIA_DEV_ID_MATCH_DEVICE_NO, \
+       .prod_id = { (v1), (v2), (v3), NULL },\
+       .prod_id_hash = { (vh1), (vh2), (vh3), 0 }, \
+       .device_no = (mfc), }
+
+/* cards needing a CIS override */
+
+#define PCMCIA_DEVICE_CIS_MANF_CARD(manf, card, _cisfile) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_FAKE_CIS | \
+                       PCMCIA_DEV_ID_MATCH_MANF_ID| \
+                       PCMCIA_DEV_ID_MATCH_CARD_ID, \
+       .manf_id = (manf), \
+       .card_id = (card), \
+       .cisfile = (_cisfile)}
+
+#define PCMCIA_DEVICE_CIS_PROD_ID12(v1, v2, vh1, vh2, _cisfile) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_FAKE_CIS | \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID2, \
+       .prod_id = { (v1), (v2), NULL, NULL }, \
+       .prod_id_hash = { (vh1), (vh2), 0, 0 }, \
+       .cisfile = (_cisfile)}
+
+#define PCMCIA_DEVICE_CIS_PROD_ID123(v1, v2, v3, vh1, vh2, vh3, _cisfile) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_FAKE_CIS | \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID3, \
+       .prod_id = { (v1), (v2), (v3), NULL },\
+       .prod_id_hash = { (vh1), (vh2), (vh3), 0 }, \
+       .cisfile = (_cisfile)}
+
+
+#define PCMCIA_DEVICE_CIS_PROD_ID2(v2, vh2, _cisfile) { \
+       .match_flags =  PCMCIA_DEV_ID_MATCH_FAKE_CIS | \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID2, \
+       .prod_id = { NULL, (v2), NULL, NULL },  \
+       .prod_id_hash = { 0, (vh2), 0, 0 }, \
+       .cisfile = (_cisfile)}
+
+#define PCMCIA_PFC_DEVICE_CIS_PROD_ID12(mfc, v1, v2, vh1, vh2, _cisfile) { \
+       .match_flags =  PCMCIA_DEV_ID_MATCH_FAKE_CIS | \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+                       PCMCIA_DEV_ID_MATCH_DEVICE_NO, \
+       .prod_id = { (v1), (v2), NULL, NULL }, \
+       .prod_id_hash = { (vh1), (vh2), 0, 0 },\
+       .device_no = (mfc), \
+       .cisfile = (_cisfile)}
+
+#define PCMCIA_MFC_DEVICE_CIS_MANF_CARD(mfc, manf, card, _cisfile) { \
+       .match_flags =  PCMCIA_DEV_ID_MATCH_FAKE_CIS | \
+                       PCMCIA_DEV_ID_MATCH_MANF_ID| \
+                       PCMCIA_DEV_ID_MATCH_CARD_ID| \
+                       PCMCIA_DEV_ID_MATCH_FUNCTION, \
+       .manf_id = (manf), \
+       .card_id = (card), \
+       .function = (mfc), \
+       .cisfile = (_cisfile)}
+
+#define PCMCIA_MFC_DEVICE_CIS_PROD_ID12(mfc, v1, v2, vh1, vh2, _cisfile) { \
+       .match_flags =  PCMCIA_DEV_ID_MATCH_FAKE_CIS | \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+                       PCMCIA_DEV_ID_MATCH_FUNCTION, \
+       .prod_id = { (v1), (v2), NULL, NULL }, \
+       .prod_id_hash = { (vh1), (vh2), 0, 0 }, \
+       .function = (mfc), \
+       .cisfile = (_cisfile)}
+
+#define PCMCIA_MFC_DEVICE_CIS_PROD_ID4(mfc, v4, vh4, _cisfile) { \
+       .match_flags =  PCMCIA_DEV_ID_MATCH_FAKE_CIS | \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID4| \
+                       PCMCIA_DEV_ID_MATCH_FUNCTION, \
+       .prod_id = { NULL, NULL, NULL, (v4) }, \
+       .prod_id_hash = { 0, 0, 0, (vh4) }, \
+       .function = (mfc), \
+       .cisfile = (_cisfile)}
+
+
+#define PCMCIA_DEVICE_NULL { .match_flags = 0, }
index 312fd95..2b52553 100644 (file)
@@ -18,6 +18,8 @@
 
 #include <pcmcia/bulkmem.h>
 #include <pcmcia/cs_types.h>
+#include <pcmcia/device_id.h>
+#include <linux/mod_devicetable.h>
 
 typedef struct tuple_parse_t {
     tuple_t            tuple;
@@ -129,12 +131,11 @@ typedef struct dev_link_t {
 
 struct pcmcia_socket;
 
-extern struct bus_type pcmcia_bus_type;
-
 struct pcmcia_driver {
        dev_link_t              *(*attach)(void);
        void                    (*detach)(dev_link_t *);
        struct module           *owner;
+       struct pcmcia_device_id *id_table;
        struct device_driver    drv;
 };
 
@@ -173,7 +174,9 @@ struct pcmcia_device {
        u8                      has_manf_id:1;
        u8                      has_card_id:1;
        u8                      has_func_id:1;
-       u8                      reserved:5;
+
+       u8                      allow_func_id_match:1;
+       u8                      reserved:4;
 
        u8                      func_id;
        u16                     manf_id;
index 67b867f..0f7aacc 100644 (file)
 #ifndef _LINUX_SS_H
 #define _LINUX_SS_H
 
+#include <linux/config.h>
+#include <linux/device.h>
+
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/bulkmem.h>
-#include <linux/device.h>
 
 /* Definitions for card status flags for GetStatus */
 #define SS_WRPROT      0x0001
@@ -171,7 +173,7 @@ typedef struct window_t {
 
 struct config_t;
 struct pcmcia_callback;
-
+struct user_info_t;
 
 struct pcmcia_socket {
        struct module                   *owner;
@@ -216,8 +218,9 @@ struct pcmcia_socket {
 
        /* is set to one if resource setup is done using adjust_resource_info() */
        u8                              resource_setup_old:1;
+       u8                              resource_setup_new:1;
 
-       u8                              reserved:6;
+       u8                              reserved:5;
 
        /* socket operations */
        struct pccard_operations *      ops;
@@ -241,9 +244,32 @@ struct pcmcia_socket {
        unsigned int                    thread_events;
 
        /* pcmcia (16-bit) */
-       struct pcmcia_bus_socket        *pcmcia;
        struct pcmcia_callback          *callback;
 
+#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE)
+       struct list_head                devices_list;   /*  PCMCIA devices */
+       u8                              device_count;   /* the number of devices, used
+                                                        * only internally and subject
+                                                        * to incorrectness and change */
+
+       struct {
+               u8                      present:1,      /* PCMCIA card is present in socket */
+                                       busy:1,         /* "master" ioctl is used */
+                                       dead:1,         /* pcmcia module is being unloaded */
+                                       device_add_pending:1, /* a pseudo-multifunction-device
+                                                              * add event is pending */
+                                       reserved:4;
+       }                               pcmcia_state;
+
+       struct work_struct              device_add;     /* for adding further pseudo-multifunction
+                                                        * devices */
+
+#ifdef CONFIG_PCMCIA_IOCTL
+       struct user_info_t              *user;
+       wait_queue_head_t               queue;
+#endif
+#endif
+
        /* cardbus (32-bit) */
 #ifdef CONFIG_CARDBUS
        struct resource *               cb_cis_res;
index 32197ef..908bff6 100644 (file)
@@ -287,6 +287,42 @@ static int do_pnp_card_entry(const char *filename,
        return 1;
 }
 
+/* Looks like: pcmcia:mNcNfNfnNpfnNvaNvbNvcNvdN. */
+static int do_pcmcia_entry(const char *filename,
+                          struct pcmcia_device_id *id, char *alias)
+{
+       unsigned int i;
+
+       id->manf_id = TO_NATIVE(id->manf_id);
+       id->card_id = TO_NATIVE(id->card_id);
+       id->func_id = TO_NATIVE(id->func_id);
+       id->function = TO_NATIVE(id->function);
+       id->device_no = TO_NATIVE(id->device_no);
+       for (i=0; i<4; i++) {
+               id->prod_id_hash[i] = TO_NATIVE(id->prod_id_hash[i]);
+       }
+
+       strcpy(alias, "pcmcia:");
+       ADD(alias, "m", id->match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID,
+          id->manf_id);
+       ADD(alias, "c", id->match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID,
+          id->card_id);
+       ADD(alias, "f", id->match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID,
+          id->func_id);
+       ADD(alias, "fn", id->match_flags & PCMCIA_DEV_ID_MATCH_FUNCTION,
+          id->function);
+       ADD(alias, "pfn", id->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO,
+          id->device_no);
+       ADD(alias, "pa", id->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1, id->prod_id_hash[0]);
+       ADD(alias, "pb", id->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2, id->prod_id_hash[1]);
+       ADD(alias, "pc", id->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3, id->prod_id_hash[2]);
+       ADD(alias, "pd", id->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4, id->prod_id_hash[3]);
+
+       return 1;
+}
+
+
+
 /* Ignore any prefix, eg. v850 prepends _ */
 static inline int sym_is(const char *symbol, const char *name)
 {
@@ -362,6 +398,9 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
        else if (sym_is(symname, "__mod_pnp_card_device_table"))
                do_table(symval, sym->st_size, sizeof(struct pnp_card_device_id),
                         do_pnp_card_entry, mod);
+       else if (sym_is(symname, "__mod_pcmcia_device_table"))
+               do_table(symval, sym->st_size, sizeof(struct pcmcia_device_id),
+                        do_pcmcia_entry, mod);
 }
 
 /* Now add out buffered information to the generated C source */
index f72c81c..2d4f8e2 100644 (file)
@@ -380,13 +380,20 @@ static int pdacf_event(event_t event, int priority, event_callback_args_t *args)
 /*
  * Module entry points
  */
+static struct pcmcia_device_id snd_pdacf_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(0x015d, 0x4c45),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, snd_pdacf_ids);
+
 static struct pcmcia_driver pdacf_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
                .name   = "snd-pdaudiocf",
        },
        .attach         = snd_pdacf_attach,
-       .detach         = snd_pdacf_detach
+       .detach         = snd_pdacf_detach,
+       .id_table       = snd_pdacf_ids,
 };
 
 static int __init init_pdacf(void)
index fce2ad0..5f4c132 100644 (file)
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-/*
- please add the following as /etc/pcmcia/vxpocket.conf:
-  device "snd-vxpocket"
-     class "audio" module "snd-vxpocket"
-
-  card "Digigram VX-POCKET"
-    manfid 0x01f1, 0x0100
-    bind "snd-vxpocket"
-
- */
 
 #include <sound/driver.h>
 #include <linux/init.h>
@@ -140,13 +129,20 @@ static void vxp_detach(dev_link_t *link)
  * Module entry points
  */
 
+static struct pcmcia_device_id vxp_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(0x01f1, 0x0100),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, vxp_ids);
+
 static struct pcmcia_driver vxp_cs_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
                .name   = DEV_INFO,
        },
        .attach         = vxp_attach,
-       .detach         = vxp_detach
+       .detach         = vxp_detach,
+       .id_table       = vxp_ids,
 };
 
 static int __init init_vxpocket(void)