Эх сурвалжийг харах

Merge /spare/repo/linux-2.6/

Jeff Garzik 20 жил өмнө
parent
commit
2179a59db1
100 өөрчлөгдсөн 5467 нэмэгдсэн , 2783 устгасан
  1. 18 6
      Documentation/Changes
  2. 64 0
      Documentation/pcmcia/devicetable.txt
  3. 51 0
      Documentation/pcmcia/driver-changes.txt
  4. 1 1
      arch/sparc64/kernel/auxio.c
  5. 4 112
      arch/sparc64/kernel/entry.S
  6. 50 121
      arch/sparc64/kernel/irq.c
  7. 8 4
      arch/sparc64/kernel/semaphore.c
  8. 0 1
      arch/sparc64/kernel/sparc64_ksyms.c
  9. 2 1
      arch/sparc64/kernel/trampoline.S
  10. 53 50
      arch/sparc64/lib/U1memcpy.S
  11. 13 2
      arch/sparc64/lib/VISsave.S
  12. 26 16
      arch/sparc64/lib/atomic.S
  13. 20 11
      arch/sparc64/lib/bitops.S
  14. 4 2
      arch/sparc64/lib/debuglocks.c
  15. 4 2
      arch/sparc64/lib/dec_and_lock.S
  16. 10 5
      arch/sparc64/lib/rwsem.S
  17. 4 2
      arch/sparc64/mm/init.c
  18. 2 1
      arch/sparc64/mm/ultra.S
  19. 24 25
      drivers/block/cfq-iosched.c
  20. 9 0
      drivers/bluetooth/bluecard_cs.c
  21. 7 0
      drivers/bluetooth/bt3c_cs.c
  22. 7 0
      drivers/bluetooth/btuart_cs.c
  23. 8 0
      drivers/bluetooth/dtl1_cs.c
  24. 8 1
      drivers/char/pcmcia/synclink_cs.c
  25. 6 0
      drivers/ide/Kconfig
  26. 4 0
      drivers/ide/ide-disk.c
  27. 0 1
      drivers/ide/ide-dma.c
  28. 2 1
      drivers/ide/ide-iops.c
  29. 35 0
      drivers/ide/legacy/ide-cs.c
  30. 1 0
      drivers/ide/pci/Makefile
  31. 48 25
      drivers/ide/pci/generic.c
  32. 228 242
      drivers/ide/pci/hpt366.c
  33. 812 0
      drivers/ide/pci/it821x.c
  34. 5 5
      drivers/ide/pci/serverworks.c
  35. 12 19
      drivers/input/gameport/gameport.c
  36. 62 27
      drivers/input/serio/serio.c
  37. 9 0
      drivers/isdn/hardware/avm/avm_cs.c
  38. 8 0
      drivers/isdn/hisax/avma1_cs.c
  39. 8 0
      drivers/isdn/hisax/elsa_cs.c
  40. 13 0
      drivers/isdn/hisax/sedlbauer_cs.c
  41. 7 0
      drivers/isdn/hisax/teles_cs.c
  42. 10 0
      drivers/mtd/maps/Kconfig
  43. 28 1
      drivers/mtd/maps/pcmciamtd.c
  44. 8 0
      drivers/net/pcmcia/3c574_cs.c
  45. 12 0
      drivers/net/pcmcia/3c589_cs.c
  46. 29 0
      drivers/net/pcmcia/axnet_cs.c
  47. 6 1
      drivers/net/pcmcia/com20020_cs.c
  48. 29 1
      drivers/net/pcmcia/fmvj18x_cs.c
  49. 8 0
      drivers/net/pcmcia/ibmtr_cs.c
  50. 8 0
      drivers/net/pcmcia/nmclan_cs.c
  51. 203 0
      drivers/net/pcmcia/pcnet_cs.c
  52. 33 0
      drivers/net/pcmcia/smc91c92_cs.c
  53. 28 0
      drivers/net/pcmcia/xirc2ps_cs.c
  54. 10 0
      drivers/net/wireless/airo_cs.c
  55. 22 0
      drivers/net/wireless/atmel_cs.c
  56. 7 0
      drivers/net/wireless/netwave_cs.c
  57. 51 0
      drivers/net/wireless/orinoco_cs.c
  58. 7 0
      drivers/net/wireless/ray_cs.c
  59. 10 0
      drivers/net/wireless/wavelan_cs.c
  60. 7 0
      drivers/net/wireless/wl3501_cs.c
  61. 9 0
      drivers/parport/parport_cs.c
  62. 35 8
      drivers/pcmcia/Kconfig
  63. 2 1
      drivers/pcmcia/Makefile
  64. 20 8
      drivers/pcmcia/cistpl.c
  65. 91 1073
      drivers/pcmcia/cs.c
  66. 6 7
      drivers/pcmcia/cs_internal.h
  67. 420 835
      drivers/pcmcia/ds.c
  68. 21 0
      drivers/pcmcia/ds_internal.h
  69. 16 7
      drivers/pcmcia/i82365.c
  70. 0 34
      drivers/pcmcia/pcmcia_compat.c
  71. 786 0
      drivers/pcmcia/pcmcia_ioctl.c
  72. 998 0
      drivers/pcmcia/pcmcia_resource.c
  73. 7 4
      drivers/pcmcia/rsrc_mgr.c
  74. 114 56
      drivers/pcmcia/rsrc_nonstatic.c
  75. 156 10
      drivers/pcmcia/socket_sysfs.c
  76. 5 1
      drivers/pcmcia/yenta_socket.c
  77. 11 0
      drivers/scsi/pcmcia/aha152x_stub.c
  78. 10 0
      drivers/scsi/pcmcia/fdomain_stub.c
  79. 13 0
      drivers/scsi/pcmcia/nsp_cs.c
  80. 22 0
      drivers/scsi/pcmcia/qlogic_stub.c
  81. 9 0
      drivers/scsi/pcmcia/sym53c500_cs.c
  82. 106 0
      drivers/serial/serial_cs.c
  83. 7 0
      drivers/telephony/ixj_pcmcia.c
  84. 8 13
      drivers/usb/host/sl811_cs.c
  85. 8 4
      include/asm-i386/ide.h
  86. 2 0
      include/asm-sparc64/auxio.h
  87. 8 8
      include/asm-sparc64/floppy.h
  88. 1 6
      include/asm-sparc64/irq.h
  89. 2 1
      include/asm-sparc64/rwsem.h
  90. 19 10
      include/asm-sparc64/spinlock.h
  91. 0 1
      include/asm-sparc64/spitfire.h
  92. 46 0
      include/linux/mod_devicetable.h
  93. 2 0
      include/linux/pci_ids.h
  94. 2 0
      include/pcmcia/ciscode.h
  95. 0 2
      include/pcmcia/cs.h
  96. 249 0
      include/pcmcia/device_id.h
  97. 6 3
      include/pcmcia/ds.h
  98. 30 4
      include/pcmcia/ss.h
  99. 39 0
      scripts/mod/file2alias.c
  100. 8 1
      sound/pcmcia/pdaudiocf/pdaudiocf.c

+ 18 - 6
Documentation/Changes

@@ -44,9 +44,9 @@ running, the suggested command should tell you.
 
 
 Again, keep in mind that this list assumes you are already
 Again, keep in mind that this list assumes you are already
 functionally running a Linux 2.4 kernel.  Also, not all tools are
 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 C                  2.95.3                  # gcc --version
 o  Gnu make               3.79.1                  # make --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  jfsutils               1.1.3                   # fsck.jfs -V
 o  reiserfsprogs          3.6.3                   # reiserfsck -V 2>&1|grep reiserfsprogs
 o  reiserfsprogs          3.6.3                   # reiserfsck -V 2>&1|grep reiserfsprogs
 o  xfsprogs               2.6.0                   # xfs_db -V
 o  xfsprogs               2.6.0                   # xfs_db -V
+o  pcmciautils            001
 o  pcmcia-cs              3.1.21                  # cardmgr -V
 o  pcmcia-cs              3.1.21                  # cardmgr -V
 o  quota-tools            3.09                    # quota -V
 o  quota-tools            3.09                    # quota -V
 o  PPP                    2.4.0                   # pppd --version
 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
 work correctly with this version of the XFS kernel code (2.6.0 or
 later is recommended, due to some significant improvements).
 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-cs
 ---------
 ---------
 
 
 PCMCIA (PC Card) support is now partially implemented in the main
 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
 Quota-tools
 -----------
 -----------
@@ -349,9 +357,13 @@ Xfsprogs
 --------
 --------
 o  <ftp://oss.sgi.com/projects/xfs/download/>
 o  <ftp://oss.sgi.com/projects/xfs/download/>
 
 
+Pcmciautils
+-----------
+o  <ftp://ftp.kernel.org/pub/linux/utils/kernel/pcmcia/>
+
 Pcmcia-cs
 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
 Quota-tools
 ----------
 ----------

+ 64 - 0
Documentation/pcmcia/devicetable.txt

@@ -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;
+}

+ 51 - 0
Documentation/pcmcia/driver-changes.txt

@@ -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".

+ 1 - 1
arch/sparc64/kernel/auxio.c

@@ -16,7 +16,7 @@
 #include <asm/ebus.h>
 #include <asm/ebus.h>
 #include <asm/auxio.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;
 void __iomem *auxio_register = NULL;
 
 
 enum auxio_type {
 enum auxio_type {

+ 4 - 112
arch/sparc64/kernel/entry.S

@@ -271,8 +271,9 @@ cplus_fptrap_insn_1:
 	fmuld		%f0, %f2, %f26
 	fmuld		%f0, %f2, %f26
 	faddd		%f0, %f2, %f28
 	faddd		%f0, %f2, %f28
 	fmuld		%f0, %f2, %f30
 	fmuld		%f0, %f2, %f30
+	membar		#Sync
 	b,pt		%xcc, fpdis_exit
 	b,pt		%xcc, fpdis_exit
-	 membar		#Sync
+	 nop
 2:	andcc		%g5, FPRS_DU, %g0
 2:	andcc		%g5, FPRS_DU, %g0
 	bne,pt		%icc, 3f
 	bne,pt		%icc, 3f
 	 fzero		%f32
 	 fzero		%f32
@@ -301,8 +302,9 @@ cplus_fptrap_insn_2:
 	fmuld		%f32, %f34, %f58
 	fmuld		%f32, %f34, %f58
 	faddd		%f32, %f34, %f60
 	faddd		%f32, %f34, %f60
 	fmuld		%f32, %f34, %f62
 	fmuld		%f32, %f34, %f62
+	membar		#Sync
 	ba,pt		%xcc, fpdis_exit
 	ba,pt		%xcc, fpdis_exit
-	 membar		#Sync
+	 nop
 3:	mov		SECONDARY_CONTEXT, %g3
 3:	mov		SECONDARY_CONTEXT, %g3
 	add		%g6, TI_FPREGS, %g1
 	add		%g6, TI_FPREGS, %g1
 	ldxa		[%g3] ASI_DMMU, %g5
 	ldxa		[%g3] ASI_DMMU, %g5
@@ -699,116 +701,6 @@ utrap_ill:
 	ba,pt		%xcc, rtrap
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 	 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 */
 	/* XXX Here is stuff we still need to write... -DaveM XXX */
 	.globl		netbsd_syscall
 	.globl		netbsd_syscall
 netbsd_syscall:
 netbsd_syscall:

+ 50 - 121
arch/sparc64/kernel/irq.c

@@ -37,6 +37,7 @@
 #include <asm/uaccess.h>
 #include <asm/uaccess.h>
 #include <asm/cache.h>
 #include <asm/cache.h>
 #include <asm/cpudata.h>
 #include <asm/cpudata.h>
+#include <asm/auxio.h>
 
 
 #ifdef CONFIG_SMP
 #ifdef CONFIG_SMP
 static void distribute_irqs(void);
 static void distribute_irqs(void);
@@ -834,137 +835,65 @@ void handler_irq(int irq, struct pt_regs *regs)
 }
 }
 
 
 #ifdef CONFIG_BLK_DEV_FD
 #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
 /* We really don't need these at all on the Sparc.  We only have
  * stubs here because they are exported to modules.
  * stubs here because they are exported to modules.

+ 8 - 4
arch/sparc64/kernel/semaphore.c

@@ -32,8 +32,9 @@ static __inline__ int __sem_update_count(struct semaphore *sem, int incr)
 "	add	%1, %4, %1\n"
 "	add	%1, %4, %1\n"
 "	cas	[%3], %0, %1\n"
 "	cas	[%3], %0, %1\n"
 "	cmp	%0, %1\n"
 "	cmp	%0, %1\n"
+"	membar	#StoreLoad | #StoreStore\n"
 "	bne,pn	%%icc, 1b\n"
 "	bne,pn	%%icc, 1b\n"
-"	 membar #StoreLoad | #StoreStore\n"
+"	 nop\n"
 	: "=&r" (old_count), "=&r" (tmp), "=m" (sem->count)
 	: "=&r" (old_count), "=&r" (tmp), "=m" (sem->count)
 	: "r" (&sem->count), "r" (incr), "m" (sem->count)
 	: "r" (&sem->count), "r" (incr), "m" (sem->count)
 	: "cc");
 	: "cc");
@@ -71,8 +72,9 @@ void up(struct semaphore *sem)
 "	cmp	%%g1, %%g7\n"
 "	cmp	%%g1, %%g7\n"
 "	bne,pn	%%icc, 1b\n"
 "	bne,pn	%%icc, 1b\n"
 "	 addcc	%%g7, 1, %%g0\n"
 "	 addcc	%%g7, 1, %%g0\n"
+"	membar	#StoreLoad | #StoreStore\n"
 "	ble,pn	%%icc, 3f\n"
 "	ble,pn	%%icc, 3f\n"
-"	 membar	#StoreLoad | #StoreStore\n"
+"	 nop\n"
 "2:\n"
 "2:\n"
 "	.subsection 2\n"
 "	.subsection 2\n"
 "3:	mov	%0, %%g1\n"
 "3:	mov	%0, %%g1\n"
@@ -128,8 +130,9 @@ void __sched down(struct semaphore *sem)
 "	cmp	%%g1, %%g7\n"
 "	cmp	%%g1, %%g7\n"
 "	bne,pn	%%icc, 1b\n"
 "	bne,pn	%%icc, 1b\n"
 "	 cmp	%%g7, 1\n"
 "	 cmp	%%g7, 1\n"
+"	membar	#StoreLoad | #StoreStore\n"
 "	bl,pn	%%icc, 3f\n"
 "	bl,pn	%%icc, 3f\n"
-"	 membar	#StoreLoad | #StoreStore\n"
+"	 nop\n"
 "2:\n"
 "2:\n"
 "	.subsection 2\n"
 "	.subsection 2\n"
 "3:	mov	%0, %%g1\n"
 "3:	mov	%0, %%g1\n"
@@ -233,8 +236,9 @@ int __sched down_interruptible(struct semaphore *sem)
 "	cmp	%%g1, %%g7\n"
 "	cmp	%%g1, %%g7\n"
 "	bne,pn	%%icc, 1b\n"
 "	bne,pn	%%icc, 1b\n"
 "	 cmp	%%g7, 1\n"
 "	 cmp	%%g7, 1\n"
+"	membar	#StoreLoad | #StoreStore\n"
 "	bl,pn	%%icc, 3f\n"
 "	bl,pn	%%icc, 3f\n"
-"	 membar	#StoreLoad | #StoreStore\n"
+"	 nop\n"
 "2:\n"
 "2:\n"
 "	.subsection 2\n"
 "	.subsection 2\n"
 "3:	mov	%2, %%g1\n"
 "3:	mov	%2, %%g1\n"

+ 0 - 1
arch/sparc64/kernel/sparc64_ksyms.c

@@ -227,7 +227,6 @@ EXPORT_SYMBOL(__flush_dcache_range);
 
 
 EXPORT_SYMBOL(mostek_lock);
 EXPORT_SYMBOL(mostek_lock);
 EXPORT_SYMBOL(mstk48t02_regs);
 EXPORT_SYMBOL(mstk48t02_regs);
-EXPORT_SYMBOL(request_fast_irq);
 #ifdef CONFIG_SUN_AUXIO
 #ifdef CONFIG_SUN_AUXIO
 EXPORT_SYMBOL(auxio_set_led);
 EXPORT_SYMBOL(auxio_set_led);
 EXPORT_SYMBOL(auxio_set_lte);
 EXPORT_SYMBOL(auxio_set_lte);

+ 2 - 1
arch/sparc64/kernel/trampoline.S

@@ -98,8 +98,9 @@ startup_continue:
 
 
 	sethi		%hi(prom_entry_lock), %g2
 	sethi		%hi(prom_entry_lock), %g2
 1:	ldstub		[%g2 + %lo(prom_entry_lock)], %g1
 1:	ldstub		[%g2 + %lo(prom_entry_lock)], %g1
+	membar		#StoreLoad | #StoreStore
 	brnz,pn		%g1, 1b
 	brnz,pn		%g1, 1b
-	 membar		#StoreLoad | #StoreStore
+	 nop
 
 
 	sethi		%hi(p1275buf), %g2
 	sethi		%hi(p1275buf), %g2
 	or		%g2, %lo(p1275buf), %g2
 	or		%g2, %lo(p1275buf), %g2

+ 53 - 50
arch/sparc64/lib/U1memcpy.S

@@ -87,14 +87,17 @@
 #define LOOP_CHUNK3(src, dest, len, branch_dest)		\
 #define LOOP_CHUNK3(src, dest, len, branch_dest)		\
 	MAIN_LOOP_CHUNK(src, dest, f32, f48, len, branch_dest)
 	MAIN_LOOP_CHUNK(src, dest, f32, f48, len, branch_dest)
 
 
+#define DO_SYNC			membar	#Sync;
 #define STORE_SYNC(dest, fsrc)				\
 #define STORE_SYNC(dest, fsrc)				\
 	EX_ST(STORE_BLK(%fsrc, %dest));			\
 	EX_ST(STORE_BLK(%fsrc, %dest));			\
-	add			%dest, 0x40, %dest;
+	add			%dest, 0x40, %dest;	\
+	DO_SYNC
 
 
 #define STORE_JUMP(dest, fsrc, target)			\
 #define STORE_JUMP(dest, fsrc, target)			\
 	EX_ST(STORE_BLK(%fsrc, %dest));			\
 	EX_ST(STORE_BLK(%fsrc, %dest));			\
 	add			%dest, 0x40, %dest;	\
 	add			%dest, 0x40, %dest;	\
-	ba,pt			%xcc, target;
+	ba,pt			%xcc, target;		\
+	 nop;
 
 
 #define FINISH_VISCHUNK(dest, f0, f1, left)	\
 #define FINISH_VISCHUNK(dest, f0, f1, left)	\
 	subcc			%left, 8, %left;\
 	subcc			%left, 8, %left;\
@@ -239,17 +242,17 @@ FUNC_NAME:		/* %o0=dst, %o1=src, %o2=len */
 	ba,pt		%xcc, 1b+4
 	ba,pt		%xcc, 1b+4
 	 faligndata	%f0, %f2, %f48
 	 faligndata	%f0, %f2, %f48
 1:	FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32)
 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)
 	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)
 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)
 	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)
 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)
 	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)
 1:	FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18)
 	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
 	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
@@ -260,17 +263,17 @@ FUNC_NAME:		/* %o0=dst, %o1=src, %o2=len */
 	ba,pt		%xcc, 1b+4
 	ba,pt		%xcc, 1b+4
 	 faligndata	%f2, %f4, %f48
 	 faligndata	%f2, %f4, %f48
 1:	FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34)
 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)
 	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)
 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)
 	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)
 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)
 	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)
 1:	FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20)
 	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
 	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
@@ -281,17 +284,17 @@ FUNC_NAME:		/* %o0=dst, %o1=src, %o2=len */
 	ba,pt		%xcc, 1b+4
 	ba,pt		%xcc, 1b+4
 	 faligndata	%f4, %f6, %f48
 	 faligndata	%f4, %f6, %f48
 1:	FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36)
 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)
 	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)
 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)
 	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)
 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)
 	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)
 1:	FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22)
 	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
 	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
@@ -302,17 +305,17 @@ FUNC_NAME:		/* %o0=dst, %o1=src, %o2=len */
 	ba,pt		%xcc, 1b+4
 	ba,pt		%xcc, 1b+4
 	 faligndata	%f6, %f8, %f48
 	 faligndata	%f6, %f8, %f48
 1:	FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38)
 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)
 	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)
 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)
 	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)
 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)
 	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)
 1:	FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24)
 	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
 	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
@@ -323,17 +326,17 @@ FUNC_NAME:		/* %o0=dst, %o1=src, %o2=len */
 	ba,pt		%xcc, 1b+4
 	ba,pt		%xcc, 1b+4
 	 faligndata	%f8, %f10, %f48
 	 faligndata	%f8, %f10, %f48
 1:	FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40)
 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)
 	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)
 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)
 	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)
 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)
 	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)
 1:	FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26)
 	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
 	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
@@ -344,17 +347,17 @@ FUNC_NAME:		/* %o0=dst, %o1=src, %o2=len */
 	ba,pt		%xcc, 1b+4
 	ba,pt		%xcc, 1b+4
 	 faligndata	%f10, %f12, %f48
 	 faligndata	%f10, %f12, %f48
 1:	FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42)
 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)
 	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)
 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)
 	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)
 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)
 	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)
 1:	FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28)
 	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
 	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
@@ -365,17 +368,17 @@ FUNC_NAME:		/* %o0=dst, %o1=src, %o2=len */
 	ba,pt		%xcc, 1b+4
 	ba,pt		%xcc, 1b+4
 	 faligndata	%f12, %f14, %f48
 	 faligndata	%f12, %f14, %f48
 1:	FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44)
 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)
 	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)
 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)
 	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)
 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)
 	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)
 1:	FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30)
 	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
 	LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
@@ -386,17 +389,17 @@ FUNC_NAME:		/* %o0=dst, %o1=src, %o2=len */
 	ba,pt		%xcc, 1b+4
 	ba,pt		%xcc, 1b+4
 	 faligndata	%f14, %f16, %f48
 	 faligndata	%f14, %f16, %f48
 1:	FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46)
 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)
 	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)
 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)
 	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)
 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)
 	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)
 40:	FINISH_VISCHUNK(o0, f0,  f2,  g3)
 41:	FINISH_VISCHUNK(o0, f2,  f4,  g3)
 41:	FINISH_VISCHUNK(o0, f2,  f4,  g3)

+ 13 - 2
arch/sparc64/lib/VISsave.S

@@ -72,7 +72,11 @@ vis1:	ldub		[%g6 + TI_FPSAVED], %g3
 
 
 	stda		%f48, [%g3 + %g1] ASI_BLK_P
 	stda		%f48, [%g3 + %g1] ASI_BLK_P
 5:	membar		#Sync
 5:	membar		#Sync
-	jmpl		%g7 + %g0, %g0
+	ba,pt		%xcc, 80f
+	 nop
+
+	.align		32
+80:	jmpl		%g7 + %g0, %g0
 	 nop
 	 nop
 
 
 6:	ldub		[%g3 + TI_FPSAVED], %o5
 6:	ldub		[%g3 + TI_FPSAVED], %o5
@@ -87,8 +91,11 @@ vis1:	ldub		[%g6 + TI_FPSAVED], %g3
 	stda		%f32, [%g2 + %g1] ASI_BLK_P
 	stda		%f32, [%g2 + %g1] ASI_BLK_P
 	stda		%f48, [%g3 + %g1] ASI_BLK_P
 	stda		%f48, [%g3 + %g1] ASI_BLK_P
 	membar		#Sync
 	membar		#Sync
-	jmpl		%g7 + %g0, %g0
+	ba,pt		%xcc, 80f
+	 nop
 
 
+	.align		32
+80:	jmpl		%g7 + %g0, %g0
 	 nop
 	 nop
 
 
 	.align		32
 	.align		32
@@ -126,6 +133,10 @@ VISenterhalf:
 	stda		%f0, [%g2 + %g1] ASI_BLK_P
 	stda		%f0, [%g2 + %g1] ASI_BLK_P
 	stda		%f16, [%g3 + %g1] ASI_BLK_P
 	stda		%f16, [%g3 + %g1] ASI_BLK_P
 	membar		#Sync
 	membar		#Sync
+	ba,pt		%xcc, 4f
+	 nop
+
+	.align		32
 4:	and		%o5, FPRS_DU, %o5
 4:	and		%o5, FPRS_DU, %o5
 	jmpl		%g7 + %g0, %g0
 	jmpl		%g7 + %g0, %g0
 	 wr		%o5, FPRS_FEF, %fprs
 	 wr		%o5, FPRS_FEF, %fprs

+ 26 - 16
arch/sparc64/lib/atomic.S

@@ -7,18 +7,6 @@
 #include <linux/config.h>
 #include <linux/config.h>
 #include <asm/asi.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
 	.text
 
 
 	/* Two versions of the atomic routines, one that
 	/* Two versions of the atomic routines, one that
@@ -52,6 +40,24 @@ atomic_sub: /* %o0 = decrement, %o1 = atomic_ptr */
 	 nop
 	 nop
 	.size	atomic_sub, .-atomic_sub
 	.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
 	.globl	atomic_add_ret
 	.type	atomic_add_ret,#function
 	.type	atomic_add_ret,#function
 atomic_add_ret: /* %o0 = increment, %o1 = atomic_ptr */
 atomic_add_ret: /* %o0 = increment, %o1 = atomic_ptr */
@@ -62,9 +68,10 @@ atomic_add_ret: /* %o0 = increment, %o1 = atomic_ptr */
 	cmp	%g1, %g7
 	cmp	%g1, %g7
 	bne,pn	%icc, 1b
 	bne,pn	%icc, 1b
 	 add	%g7, %o0, %g7
 	 add	%g7, %o0, %g7
+	sra	%g7, 0, %o0
 	ATOMIC_POST_BARRIER
 	ATOMIC_POST_BARRIER
 	retl
 	retl
-	 sra	%g7, 0, %o0
+	 nop
 	.size	atomic_add_ret, .-atomic_add_ret
 	.size	atomic_add_ret, .-atomic_add_ret
 
 
 	.globl	atomic_sub_ret
 	.globl	atomic_sub_ret
@@ -77,9 +84,10 @@ atomic_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */
 	cmp	%g1, %g7
 	cmp	%g1, %g7
 	bne,pn	%icc, 1b
 	bne,pn	%icc, 1b
 	 sub	%g7, %o0, %g7
 	 sub	%g7, %o0, %g7
+	sra	%g7, 0, %o0
 	ATOMIC_POST_BARRIER
 	ATOMIC_POST_BARRIER
 	retl
 	retl
-	 sra	%g7, 0, %o0
+	 nop
 	.size	atomic_sub_ret, .-atomic_sub_ret
 	.size	atomic_sub_ret, .-atomic_sub_ret
 
 
 	.globl	atomic64_add
 	.globl	atomic64_add
@@ -118,9 +126,10 @@ atomic64_add_ret: /* %o0 = increment, %o1 = atomic_ptr */
 	cmp	%g1, %g7
 	cmp	%g1, %g7
 	bne,pn	%xcc, 1b
 	bne,pn	%xcc, 1b
 	 add	%g7, %o0, %g7
 	 add	%g7, %o0, %g7
+	mov	%g7, %o0
 	ATOMIC_POST_BARRIER
 	ATOMIC_POST_BARRIER
 	retl
 	retl
-	 mov	%g7, %o0
+	 nop
 	.size	atomic64_add_ret, .-atomic64_add_ret
 	.size	atomic64_add_ret, .-atomic64_add_ret
 
 
 	.globl	atomic64_sub_ret
 	.globl	atomic64_sub_ret
@@ -133,7 +142,8 @@ atomic64_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */
 	cmp	%g1, %g7
 	cmp	%g1, %g7
 	bne,pn	%xcc, 1b
 	bne,pn	%xcc, 1b
 	 sub	%g7, %o0, %g7
 	 sub	%g7, %o0, %g7
+	mov	%g7, %o0
 	ATOMIC_POST_BARRIER
 	ATOMIC_POST_BARRIER
 	retl
 	retl
-	 mov	%g7, %o0
+	 nop
 	.size	atomic64_sub_ret, .-atomic64_sub_ret
 	.size	atomic64_sub_ret, .-atomic64_sub_ret

+ 20 - 11
arch/sparc64/lib/bitops.S

@@ -7,20 +7,26 @@
 #include <linux/config.h>
 #include <linux/config.h>
 #include <asm/asi.h>
 #include <asm/asi.h>
 
 
+	.text
+
 	/* On SMP we need to use memory barriers to ensure
 	/* On SMP we need to use memory barriers to ensure
 	 * correct memory operation ordering, nop these out
 	 * correct memory operation ordering, nop these out
 	 * for uniprocessor.
 	 * for uniprocessor.
 	 */
 	 */
+
 #ifdef CONFIG_SMP
 #ifdef CONFIG_SMP
 #define BITOP_PRE_BARRIER	membar #StoreLoad | #LoadLoad
 #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
 #else
-#define BITOP_PRE_BARRIER	nop
-#define BITOP_POST_BARRIER	nop
+#define BITOP_PRE_BARRIER
+#define BITOP_POST_BARRIER
 #endif
 #endif
 
 
-	.text
-
 	.globl	test_and_set_bit
 	.globl	test_and_set_bit
 	.type	test_and_set_bit,#function
 	.type	test_and_set_bit,#function
 test_and_set_bit:	/* %o0=nr, %o1=addr */
 test_and_set_bit:	/* %o0=nr, %o1=addr */
@@ -37,10 +43,11 @@ test_and_set_bit:	/* %o0=nr, %o1=addr */
 	cmp	%g7, %g1
 	cmp	%g7, %g1
 	bne,pn	%xcc, 1b
 	bne,pn	%xcc, 1b
 	 and	%g7, %o2, %g2
 	 and	%g7, %o2, %g2
-	BITOP_POST_BARRIER
 	clr	%o0
 	clr	%o0
+	movrne	%g2, 1, %o0
+	BITOP_POST_BARRIER
 	retl
 	retl
-	 movrne	%g2, 1, %o0
+	 nop
 	.size	test_and_set_bit, .-test_and_set_bit
 	.size	test_and_set_bit, .-test_and_set_bit
 
 
 	.globl	test_and_clear_bit
 	.globl	test_and_clear_bit
@@ -59,10 +66,11 @@ test_and_clear_bit:	/* %o0=nr, %o1=addr */
 	cmp	%g7, %g1
 	cmp	%g7, %g1
 	bne,pn	%xcc, 1b
 	bne,pn	%xcc, 1b
 	 and	%g7, %o2, %g2
 	 and	%g7, %o2, %g2
-	BITOP_POST_BARRIER
 	clr	%o0
 	clr	%o0
+	movrne	%g2, 1, %o0
+	BITOP_POST_BARRIER
 	retl
 	retl
-	 movrne	%g2, 1, %o0
+	 nop
 	.size	test_and_clear_bit, .-test_and_clear_bit
 	.size	test_and_clear_bit, .-test_and_clear_bit
 
 
 	.globl	test_and_change_bit
 	.globl	test_and_change_bit
@@ -81,10 +89,11 @@ test_and_change_bit:	/* %o0=nr, %o1=addr */
 	cmp	%g7, %g1
 	cmp	%g7, %g1
 	bne,pn	%xcc, 1b
 	bne,pn	%xcc, 1b
 	 and	%g7, %o2, %g2
 	 and	%g7, %o2, %g2
-	BITOP_POST_BARRIER
 	clr	%o0
 	clr	%o0
+	movrne	%g2, 1, %o0
+	BITOP_POST_BARRIER
 	retl
 	retl
-	 movrne	%g2, 1, %o0
+	 nop
 	.size	test_and_change_bit, .-test_and_change_bit
 	.size	test_and_change_bit, .-test_and_change_bit
 
 
 	.globl	set_bit
 	.globl	set_bit

+ 4 - 2
arch/sparc64/lib/debuglocks.c

@@ -252,8 +252,9 @@ wlock_again:
 "		andn	%%g1, %%g3, %%g7\n"
 "		andn	%%g1, %%g3, %%g7\n"
 "		casx	[%0], %%g1, %%g7\n"
 "		casx	[%0], %%g1, %%g7\n"
 "		cmp	%%g1, %%g7\n"
 "		cmp	%%g1, %%g7\n"
+"		membar	#StoreLoad | #StoreStore\n"
 "		bne,pn	%%xcc, 1b\n"
 "		bne,pn	%%xcc, 1b\n"
-"		 membar	#StoreLoad | #StoreStore"
+"		 nop"
 		: /* no outputs */
 		: /* no outputs */
 		: "r" (&(rw->lock))
 		: "r" (&(rw->lock))
 		: "g3", "g1", "g7", "cc", "memory");
 		: "g3", "g1", "g7", "cc", "memory");
@@ -351,8 +352,9 @@ int _do_write_trylock (rwlock_t *rw, char *str)
 "		andn	%%g1, %%g3, %%g7\n"
 "		andn	%%g1, %%g3, %%g7\n"
 "		casx	[%0], %%g1, %%g7\n"
 "		casx	[%0], %%g1, %%g7\n"
 "		cmp	%%g1, %%g7\n"
 "		cmp	%%g1, %%g7\n"
+"		membar	#StoreLoad | #StoreStore\n"
 "		bne,pn	%%xcc, 1b\n"
 "		bne,pn	%%xcc, 1b\n"
-"		 membar	#StoreLoad | #StoreStore"
+"		 nop"
 		: /* no outputs */
 		: /* no outputs */
 		: "r" (&(rw->lock))
 		: "r" (&(rw->lock))
 		: "g3", "g1", "g7", "cc", "memory");
 		: "g3", "g1", "g7", "cc", "memory");

+ 4 - 2
arch/sparc64/lib/dec_and_lock.S

@@ -48,8 +48,9 @@ start_to_zero:
 #endif
 #endif
 to_zero:
 to_zero:
 	ldstub	[%o1], %g3
 	ldstub	[%o1], %g3
+	membar	#StoreLoad | #StoreStore
 	brnz,pn	%g3, spin_on_lock
 	brnz,pn	%g3, spin_on_lock
-	 membar	#StoreLoad | #StoreStore
+	 nop
 loop2:	cas	[%o0], %g2, %g7		/* ASSERT(g7 == 0) */
 loop2:	cas	[%o0], %g2, %g7		/* ASSERT(g7 == 0) */
 	cmp	%g2, %g7
 	cmp	%g2, %g7
 
 
@@ -71,8 +72,9 @@ loop2:	cas	[%o0], %g2, %g7		/* ASSERT(g7 == 0) */
 	 nop
 	 nop
 spin_on_lock:
 spin_on_lock:
 	ldub	[%o1], %g3
 	ldub	[%o1], %g3
+	membar	#LoadLoad
 	brnz,pt	%g3, spin_on_lock
 	brnz,pt	%g3, spin_on_lock
-	 membar	#LoadLoad
+	 nop
 	ba,pt	%xcc, to_zero
 	ba,pt	%xcc, to_zero
 	 nop
 	 nop
 	nop
 	nop

+ 10 - 5
arch/sparc64/lib/rwsem.S

@@ -17,8 +17,9 @@ __down_read:
 	bne,pn		%icc, 1b
 	bne,pn		%icc, 1b
 	 add		%g7, 1, %g7
 	 add		%g7, 1, %g7
 	cmp		%g7, 0
 	cmp		%g7, 0
+	membar		#StoreLoad | #StoreStore
 	bl,pn		%icc, 3f
 	bl,pn		%icc, 3f
-	 membar		#StoreLoad | #StoreStore
+	 nop
 2:
 2:
 	retl
 	retl
 	 nop
 	 nop
@@ -57,8 +58,9 @@ __down_write:
 	cmp		%g3, %g7
 	cmp		%g3, %g7
 	bne,pn		%icc, 1b
 	bne,pn		%icc, 1b
 	 cmp		%g7, 0
 	 cmp		%g7, 0
+	membar		#StoreLoad | #StoreStore
 	bne,pn		%icc, 3f
 	bne,pn		%icc, 3f
-	 membar		#StoreLoad | #StoreStore
+	 nop
 2:	retl
 2:	retl
 	 nop
 	 nop
 3:
 3:
@@ -97,8 +99,9 @@ __up_read:
 	cmp		%g1, %g7
 	cmp		%g1, %g7
 	bne,pn		%icc, 1b
 	bne,pn		%icc, 1b
 	 cmp		%g7, 0
 	 cmp		%g7, 0
+	membar		#StoreLoad | #StoreStore
 	bl,pn		%icc, 3f
 	bl,pn		%icc, 3f
-	 membar		#StoreLoad | #StoreStore
+	 nop
 2:	retl
 2:	retl
 	 nop
 	 nop
 3:	sethi		%hi(RWSEM_ACTIVE_MASK), %g1
 3:	sethi		%hi(RWSEM_ACTIVE_MASK), %g1
@@ -126,8 +129,9 @@ __up_write:
 	bne,pn		%icc, 1b
 	bne,pn		%icc, 1b
 	 sub		%g7, %g1, %g7
 	 sub		%g7, %g1, %g7
 	cmp		%g7, 0
 	cmp		%g7, 0
+	membar		#StoreLoad | #StoreStore
 	bl,pn		%icc, 3f
 	bl,pn		%icc, 3f
-	 membar		#StoreLoad | #StoreStore
+	 nop
 2:
 2:
 	retl
 	retl
 	 nop
 	 nop
@@ -151,8 +155,9 @@ __downgrade_write:
 	bne,pn		%icc, 1b
 	bne,pn		%icc, 1b
 	 sub		%g7, %g1, %g7
 	 sub		%g7, %g1, %g7
 	cmp		%g7, 0
 	cmp		%g7, 0
+	membar		#StoreLoad | #StoreStore
 	bl,pn		%icc, 3f
 	bl,pn		%icc, 3f
-	 membar		#StoreLoad | #StoreStore
+	 nop
 2:
 2:
 	retl
 	retl
 	 nop
 	 nop

+ 4 - 2
arch/sparc64/mm/init.c

@@ -136,8 +136,9 @@ static __inline__ void set_dcache_dirty(struct page *page, int this_cpu)
 			     "or	%%g1, %0, %%g1\n\t"
 			     "or	%%g1, %0, %%g1\n\t"
 			     "casx	[%2], %%g7, %%g1\n\t"
 			     "casx	[%2], %%g7, %%g1\n\t"
 			     "cmp	%%g7, %%g1\n\t"
 			     "cmp	%%g7, %%g1\n\t"
+			     "membar	#StoreLoad | #StoreStore\n\t"
 			     "bne,pn	%%xcc, 1b\n\t"
 			     "bne,pn	%%xcc, 1b\n\t"
-			     " membar	#StoreLoad | #StoreStore"
+			     " nop"
 			     : /* no outputs */
 			     : /* no outputs */
 			     : "r" (mask), "r" (non_cpu_bits), "r" (&page->flags)
 			     : "r" (mask), "r" (non_cpu_bits), "r" (&page->flags)
 			     : "g1", "g7");
 			     : "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"
 			     " andn	%%g7, %1, %%g1\n\t"
 			     "casx	[%2], %%g7, %%g1\n\t"
 			     "casx	[%2], %%g7, %%g1\n\t"
 			     "cmp	%%g7, %%g1\n\t"
 			     "cmp	%%g7, %%g1\n\t"
+			     "membar	#StoreLoad | #StoreStore\n\t"
 			     "bne,pn	%%xcc, 1b\n\t"
 			     "bne,pn	%%xcc, 1b\n\t"
-			     " membar	#StoreLoad | #StoreStore\n"
+			     " nop\n"
 			     "2:"
 			     "2:"
 			     : /* no outputs */
 			     : /* no outputs */
 			     : "r" (cpu), "r" (mask), "r" (&page->flags),
 			     : "r" (cpu), "r" (mask), "r" (&page->flags),

+ 2 - 1
arch/sparc64/mm/ultra.S

@@ -266,8 +266,9 @@ __cheetah_flush_tlb_pending:	/* 22 insns */
 	 andn		%o3, 1, %o3
 	 andn		%o3, 1, %o3
 	stxa		%g0, [%o3] ASI_IMMU_DEMAP
 	stxa		%g0, [%o3] ASI_IMMU_DEMAP
 2:	stxa		%g0, [%o3] ASI_DMMU_DEMAP	
 2:	stxa		%g0, [%o3] ASI_DMMU_DEMAP	
+	membar		#Sync
 	brnz,pt		%o1, 1b
 	brnz,pt		%o1, 1b
-	 membar		#Sync
+	 nop
 	stxa		%g2, [%o4] ASI_DMMU
 	stxa		%g2, [%o4] ASI_DMMU
 	flush		%g6
 	flush		%g6
 	wrpr		%g0, 0, %tl
 	wrpr		%g0, 0, %tl

+ 24 - 25
drivers/block/cfq-iosched.c

@@ -300,7 +300,6 @@ CFQ_CRQ_FNS(requeued);
 static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned int, unsigned short);
 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_dispatch_sort(request_queue_t *, struct cfq_rq *);
 static void cfq_put_cfqd(struct cfq_data *cfqd);
 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)
 #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;
 	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.
  * 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
  * 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));
 	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
  * 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)
 static void cfq_completed_request(request_queue_t *q, struct request *rq)
 {
 {
 	struct cfq_rq *crq = RQ_DATA(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 1
 	if ((cfq_cfqq_wait_request(cfqq) || cfq_cfqq_must_alloc(cfqq)) &&
 	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);
 		cfq_mark_cfqq_must_alloc_slice(cfqq);
 		return ELV_MQUEUE_MUST;
 		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
 		 * only allow 1 ELV_MQUEUE_MUST per slice, otherwise we
 		 * can quickly flood the queue with writes from a single task
 		 * 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);
 			cfq_mark_cfqq_must_alloc_slice(cfqq);
 			return ELV_MQUEUE_MUST;
 			return ELV_MQUEUE_MUST;
 		}
 		}

+ 9 - 0
drivers/bluetooth/bluecard_cs.c

@@ -1089,6 +1089,14 @@ static int bluecard_event(event_t event, int priority, event_callback_args_t *ar
 	return 0;
 	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 = {
 static struct pcmcia_driver bluecard_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -1096,6 +1104,7 @@ static struct pcmcia_driver bluecard_driver = {
 	},
 	},
 	.attach		= bluecard_attach,
 	.attach		= bluecard_attach,
 	.detach		= bluecard_detach,
 	.detach		= bluecard_detach,
+	.id_table	= bluecard_ids,
 };
 };
 
 
 static int __init init_bluecard_cs(void)
 static int __init init_bluecard_cs(void)

+ 7 - 0
drivers/bluetooth/bt3c_cs.c

@@ -935,6 +935,12 @@ static int bt3c_event(event_t event, int priority, event_callback_args_t *args)
 	return 0;
 	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 = {
 static struct pcmcia_driver bt3c_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -942,6 +948,7 @@ static struct pcmcia_driver bt3c_driver = {
 	},
 	},
 	.attach		= bt3c_attach,
 	.attach		= bt3c_attach,
 	.detach		= bt3c_detach,
 	.detach		= bt3c_detach,
+	.id_table	= bt3c_ids,
 };
 };
 
 
 static int __init init_bt3c_cs(void)
 static int __init init_bt3c_cs(void)

+ 7 - 0
drivers/bluetooth/btuart_cs.c

@@ -855,6 +855,12 @@ static int btuart_event(event_t event, int priority, event_callback_args_t *args
 	return 0;
 	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 = {
 static struct pcmcia_driver btuart_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -862,6 +868,7 @@ static struct pcmcia_driver btuart_driver = {
 	},
 	},
 	.attach		= btuart_attach,
 	.attach		= btuart_attach,
 	.detach		= btuart_detach,
 	.detach		= btuart_detach,
+	.id_table	= btuart_ids,
 };
 };
 
 
 static int __init init_btuart_cs(void)
 static int __init init_btuart_cs(void)

+ 8 - 0
drivers/bluetooth/dtl1_cs.c

@@ -807,6 +807,13 @@ static int dtl1_event(event_t event, int priority, event_callback_args_t *args)
 	return 0;
 	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 = {
 static struct pcmcia_driver dtl1_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -814,6 +821,7 @@ static struct pcmcia_driver dtl1_driver = {
 	},
 	},
 	.attach		= dtl1_attach,
 	.attach		= dtl1_attach,
 	.detach		= dtl1_detach,
 	.detach		= dtl1_detach,
+	.id_table	= dtl1_ids,
 };
 };
 
 
 static int __init init_dtl1_cs(void)
 static int __init init_dtl1_cs(void)

+ 8 - 1
drivers/char/pcmcia/synclink_cs.c

@@ -581,7 +581,7 @@ static dev_link_t *mgslpc_attach(void)
 
 
     /* Interrupt setup */
     /* Interrupt setup */
     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
     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->irq.Handler = NULL;
     
     
     link->conf.Attributes = 0;
     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 = {
 static struct pcmcia_driver mgslpc_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -3088,6 +3094,7 @@ static struct pcmcia_driver mgslpc_driver = {
 	},
 	},
 	.attach		= mgslpc_attach,
 	.attach		= mgslpc_attach,
 	.detach		= mgslpc_detach,
 	.detach		= mgslpc_detach,
+	.id_table	= mgslpc_ids,
 };
 };
 
 
 static struct tty_operations mgslpc_ops = {
 static struct tty_operations mgslpc_ops = {

+ 6 - 0
drivers/ide/Kconfig

@@ -606,6 +606,12 @@ config BLK_DEV_IT8172
 	  <http://www.ite.com.tw/ia/brief_it8172bsp.htm>; picture of the
 	  <http://www.ite.com.tw/ia/brief_it8172bsp.htm>; picture of the
 	  board at <http://www.mvista.com/partners/semiconductor/ite.html>.
 	  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
 config BLK_DEV_NS87415
 	tristate "NS87415 chipset support"
 	tristate "NS87415 chipset support"
 	help
 	help

+ 4 - 0
drivers/ide/ide-disk.c

@@ -119,6 +119,10 @@ static int lba_capacity_is_ok (struct hd_driveid *id)
 {
 {
 	unsigned long lba_sects, chs_sects, head, tail;
 	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
 	 * The ATA spec tells large drives to return
 	 * C/H/S = 16383/16/63 independent of their size.
 	 * C/H/S = 16383/16/63 independent of their size.

+ 0 - 1
drivers/ide/ide-dma.c

@@ -132,7 +132,6 @@ static const struct drive_list_entry drive_blacklist [] = {
 	{ "SAMSUNG CD-ROM SC-148C",	"ALL"		},
 	{ "SAMSUNG CD-ROM SC-148C",	"ALL"		},
 	{ "SAMSUNG CD-ROM SC",	"ALL"		},
 	{ "SAMSUNG CD-ROM SC",	"ALL"		},
 	{ "SanDisk SDP3B-64"	,	"ALL"		},
 	{ "SanDisk SDP3B-64"	,	"ALL"		},
-	{ "SAMSUNG CD-ROM SN-124",	"ALL"		},
 	{ "ATAPI CD-ROM DRIVE 40X MAXIMUM",	"ALL"		},
 	{ "ATAPI CD-ROM DRIVE 40X MAXIMUM",	"ALL"		},
 	{ "_NEC DV5800A",               "ALL"           },  
 	{ "_NEC DV5800A",               "ALL"           },  
 	{ NULL			,	NULL		}
 	{ NULL			,	NULL		}

+ 2 - 1
drivers/ide/ide-iops.c

@@ -1181,7 +1181,8 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
 		pre_reset(drive);
 		pre_reset(drive);
 		SELECT_DRIVE(drive);
 		SELECT_DRIVE(drive);
 		udelay (20);
 		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->poll_timeout = jiffies + WAIT_WORSTCASE;
 		hwgroup->polling = 1;
 		hwgroup->polling = 1;
 		__ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
 		__ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);

+ 35 - 0
drivers/ide/legacy/ide-cs.c

@@ -457,6 +457,40 @@ int ide_event(event_t event, int priority,
     return 0;
     return 0;
 } /* ide_event */
 } /* 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 = {
 static struct pcmcia_driver ide_cs_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -464,6 +498,7 @@ static struct pcmcia_driver ide_cs_driver = {
 	},
 	},
 	.attach		= ide_attach,
 	.attach		= ide_attach,
 	.detach		= ide_detach,
 	.detach		= ide_detach,
+	.id_table       = ide_ids,
 };
 };
 
 
 static int __init init_ide_cs(void)
 static int __init init_ide_cs(void)

+ 1 - 0
drivers/ide/pci/Makefile

@@ -12,6 +12,7 @@ obj-$(CONFIG_BLK_DEV_HPT34X)		+= hpt34x.o
 obj-$(CONFIG_BLK_DEV_HPT366)		+= hpt366.o
 obj-$(CONFIG_BLK_DEV_HPT366)		+= hpt366.o
 #obj-$(CONFIG_BLK_DEV_HPT37X)		+= hpt37x.o
 #obj-$(CONFIG_BLK_DEV_HPT37X)		+= hpt37x.o
 obj-$(CONFIG_BLK_DEV_IT8172)		+= it8172.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_NS87415)		+= ns87415.o
 obj-$(CONFIG_BLK_DEV_OPTI621)		+= opti621.o
 obj-$(CONFIG_BLK_DEV_OPTI621)		+= opti621.o
 obj-$(CONFIG_BLK_DEV_PDC202XX_OLD)	+= pdc202xx_old.o
 obj-$(CONFIG_BLK_DEV_PDC202XX_OLD)	+= pdc202xx_old.o

+ 48 - 25
drivers/ide/pci/generic.c

@@ -39,6 +39,17 @@
 
 
 #include <asm/io.h>
 #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)
 static void __devinit init_hwif_generic (ide_hwif_t *hwif)
 {
 {
 	switch(hwif->pci_dev->device) {
 	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 = {
 static ide_pci_device_t generic_chipsets[] __devinitdata = {
 	{	/* 0 */
 	{	/* 0 */
+		.name		= "Unknown",
+		.init_hwif	= init_hwif_generic,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.bootable	= ON_BOARD,
+	},{	/* 1 */
 		.name		= "NS87410",
 		.name		= "NS87410",
 		.init_hwif	= init_hwif_generic,
 		.init_hwif	= init_hwif_generic,
 		.channels	= 2,
 		.channels	= 2,
 		.autodma	= AUTODMA,
 		.autodma	= AUTODMA,
 		.enablebits	= {{0x43,0x08,0x08}, {0x47,0x08,0x08}},
 		.enablebits	= {{0x43,0x08,0x08}, {0x47,0x08,0x08}},
 		.bootable	= ON_BOARD,
 		.bootable	= ON_BOARD,
-        },{	/* 1 */
+        },{	/* 2 */
 		.name		= "SAMURAI",
 		.name		= "SAMURAI",
 		.init_hwif	= init_hwif_generic,
 		.init_hwif	= init_hwif_generic,
 		.channels	= 2,
 		.channels	= 2,
 		.autodma	= AUTODMA,
 		.autodma	= AUTODMA,
 		.bootable	= ON_BOARD,
 		.bootable	= ON_BOARD,
-	},{	/* 2 */
+	},{	/* 3 */
 		.name		= "HT6565",
 		.name		= "HT6565",
 		.init_hwif	= init_hwif_generic,
 		.init_hwif	= init_hwif_generic,
 		.channels	= 2,
 		.channels	= 2,
 		.autodma	= AUTODMA,
 		.autodma	= AUTODMA,
 		.bootable	= ON_BOARD,
 		.bootable	= ON_BOARD,
-	},{	/* 3 */
+	},{	/* 4 */
 		.name		= "UM8673F",
 		.name		= "UM8673F",
 		.init_hwif	= init_hwif_generic,
 		.init_hwif	= init_hwif_generic,
 		.channels	= 2,
 		.channels	= 2,
 		.autodma	= NODMA,
 		.autodma	= NODMA,
 		.bootable	= ON_BOARD,
 		.bootable	= ON_BOARD,
-	},{	/* 4 */
+	},{	/* 5 */
 		.name		= "UM8886A",
 		.name		= "UM8886A",
 		.init_hwif	= init_hwif_generic,
 		.init_hwif	= init_hwif_generic,
 		.channels	= 2,
 		.channels	= 2,
 		.autodma	= NODMA,
 		.autodma	= NODMA,
 		.bootable	= ON_BOARD,
 		.bootable	= ON_BOARD,
-	},{	/* 5 */
+	},{	/* 6 */
 		.name		= "UM8886BF",
 		.name		= "UM8886BF",
 		.init_hwif	= init_hwif_generic,
 		.init_hwif	= init_hwif_generic,
 		.channels	= 2,
 		.channels	= 2,
 		.autodma	= NODMA,
 		.autodma	= NODMA,
 		.bootable	= ON_BOARD,
 		.bootable	= ON_BOARD,
-	},{	/* 6 */
+	},{	/* 7 */
 		.name		= "HINT_IDE",
 		.name		= "HINT_IDE",
 		.init_hwif	= init_hwif_generic,
 		.init_hwif	= init_hwif_generic,
 		.channels	= 2,
 		.channels	= 2,
 		.autodma	= AUTODMA,
 		.autodma	= AUTODMA,
 		.bootable	= ON_BOARD,
 		.bootable	= ON_BOARD,
-	},{	/* 7 */
+	},{	/* 8 */
 		.name		= "VIA_IDE",
 		.name		= "VIA_IDE",
 		.init_hwif	= init_hwif_generic,
 		.init_hwif	= init_hwif_generic,
 		.channels	= 2,
 		.channels	= 2,
 		.autodma	= NOAUTODMA,
 		.autodma	= NOAUTODMA,
 		.bootable	= ON_BOARD,
 		.bootable	= ON_BOARD,
-	},{	/* 8 */
+	},{	/* 9 */
 		.name		= "OPTI621V",
 		.name		= "OPTI621V",
 		.init_hwif	= init_hwif_generic,
 		.init_hwif	= init_hwif_generic,
 		.channels	= 2,
 		.channels	= 2,
 		.autodma	= NOAUTODMA,
 		.autodma	= NOAUTODMA,
 		.bootable	= ON_BOARD,
 		.bootable	= ON_BOARD,
-	},{	/* 9 */
+	},{	/* 10 */
 		.name		= "VIA8237SATA",
 		.name		= "VIA8237SATA",
 		.init_hwif	= init_hwif_generic,
 		.init_hwif	= init_hwif_generic,
 		.channels	= 2,
 		.channels	= 2,
 		.autodma	= AUTODMA,
 		.autodma	= AUTODMA,
 		.bootable	= OFF_BOARD,
 		.bootable	= OFF_BOARD,
-	},{	/* 10 */
+	},{	/* 11 */
 		.name 		= "Piccolo0102",
 		.name 		= "Piccolo0102",
 		.init_hwif	= init_hwif_generic,
 		.init_hwif	= init_hwif_generic,
 		.channels	= 2,
 		.channels	= 2,
 		.autodma	= NOAUTODMA,
 		.autodma	= NOAUTODMA,
 		.bootable	= ON_BOARD,
 		.bootable	= ON_BOARD,
-	},{	/* 11 */
+	},{	/* 12 */
 		.name 		= "Piccolo0103",
 		.name 		= "Piccolo0103",
 		.init_hwif	= init_hwif_generic,
 		.init_hwif	= init_hwif_generic,
 		.channels	= 2,
 		.channels	= 2,
 		.autodma	= NOAUTODMA,
 		.autodma	= NOAUTODMA,
 		.bootable	= ON_BOARD,
 		.bootable	= ON_BOARD,
-	},{	/* 12 */
+	},{	/* 13 */
 		.name 		= "Piccolo0105",
 		.name 		= "Piccolo0105",
 		.init_hwif	= init_hwif_generic,
 		.init_hwif	= init_hwif_generic,
 		.channels	= 2,
 		.channels	= 2,
@@ -174,6 +191,10 @@ static int __devinit generic_init_one(struct pci_dev *dev, const struct pci_devi
 	u16 command;
 	u16 command;
 	int ret = -ENODEV;
 	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 &&
 	if (dev->vendor == PCI_VENDOR_ID_UMC &&
 	    dev->device == PCI_DEVICE_ID_UMC_UM8886A &&
 	    dev->device == PCI_DEVICE_ID_UMC_UM8886A &&
 	    (!(PCI_FUNC(dev->devfn) & 1)))
 	    (!(PCI_FUNC(dev->devfn) & 1)))
@@ -195,21 +216,23 @@ out:
 }
 }
 
 
 static struct pci_device_id generic_pci_tbl[] = {
 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
 #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
 #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, },
 	{ 0, },
 };
 };
 MODULE_DEVICE_TABLE(pci, generic_pci_tbl);
 MODULE_DEVICE_TABLE(pci, generic_pci_tbl);

+ 228 - 242
drivers/ide/pci/hpt366.c

@@ -10,6 +10,11 @@
  * donation of an ABit BP6 mainboard, processor, and memory acellerated
  * donation of an ABit BP6 mainboard, processor, and memory acellerated
  * development and support.
  * 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.
  * Note that final HPT370 support was done by force extraction of GPL.
  *
  *
  * - add function for getting/setting power status of drive
  * - 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_50	0x2d
 #define F_LOW_PCI_66	0x42
 #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;
 	u32 class_rev;
 	pci_read_config_dword(dev, PCI_CLASS_REVISION, &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;
 	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 int check_in_drive_lists(ide_drive_t *drive, const char **list);
 
 
 static u8 hpt3xx_ratemask (ide_drive_t *drive)
 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;
 	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;
 		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;
 		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;
 		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;
 		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;
 		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 = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
 		mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : mode;
 		mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : mode;
 	} else {				/* HPT366 and HPT368 */
 	} else {				/* HPT366 and HPT368 */
 		mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : 2;
 		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);
 		mode = min(mode, (u8)1);
 	return mode;
 	return mode;
 }
 }
@@ -549,7 +535,8 @@ static u8 hpt3xx_ratemask (ide_drive_t *drive)
  
  
 static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
 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);
 	u8 mode			= hpt3xx_ratemask(drive);
 
 
 	if (drive->media != ide_disk)
 	if (drive->media != ide_disk)
@@ -561,7 +548,7 @@ static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
 			break;
 			break;
 		case 0x03:
 		case 0x03:
 			speed = min(speed, (u8)XFER_UDMA_5);
 			speed = min(speed, (u8)XFER_UDMA_5);
-			if (hpt_minimum_revision(dev, 5))
+			if (info->revision >= 5)
 				break;
 				break;
 			if (check_in_drive_lists(drive, bad_ata100_5))
 			if (check_in_drive_lists(drive, bad_ata100_5))
 				speed = min(speed, (u8)XFER_UDMA_4);
 				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 ??
 	 * CHECK ME, Does this need to be set to 5 ??
 	 */
 	 */
-			if (hpt_minimum_revision(dev, 3))
+			if (info->revision >= 3)
 				break;
 				break;
 			if ((check_in_drive_lists(drive, bad_ata66_4)) ||
 			if ((check_in_drive_lists(drive, bad_ata66_4)) ||
 			    (!(HPT366_ALLOW_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 ??
 	 * CHECK ME, Does this need to be set to 5 ??
 	 */
 	 */
-			if (hpt_minimum_revision(dev, 3))
+			if (info->revision >= 3)
 				break;
 				break;
 			if (check_in_drive_lists(drive, bad_ata33))
 			if (check_in_drive_lists(drive, bad_ata33))
 				speed = min(speed, (u8)XFER_MW_DMA_2);
 				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)
 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		= hpt3xx_ratefilter(drive, xferspeed);
-//	u8 speed		= ide_rate_filter(hpt3xx_ratemask(drive), xferspeed);
 	u8 regtime		= (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
 	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;
 	u8 drive_fast		= 0;
 	u32 reg1 = 0, reg2	= 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.
 	 * Disable the "fast interrupt" prediction.
 	 */
 	 */
 	pci_read_config_byte(dev, regfast, &drive_fast);
 	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)
 	if (drive_fast & 0x80)
 		pci_write_config_byte(dev, regfast, 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
 	 * Disable on-chip PIO FIFO/buffer
 	 *  (to avoid problems handling I/O errors later)
 	 *  (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)
 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	= 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 drive_pci	= 0x40 + (drive->dn * 4);
 	u8 new_fast	= 0, drive_fast = 0;
 	u8 new_fast	= 0, drive_fast = 0;
 	u32 list_conf	= 0, drive_conf = 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)
 	if (new_fast != drive_fast)
 		pci_write_config_byte(dev, regfast, new_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);
 	pci_read_config_dword(dev, drive_pci, &drive_conf);
 	list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
 	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 */
 		list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
-	}
-
 	pci_write_config_dword(dev, drive_pci, list_conf);
 	pci_write_config_dword(dev, drive_pci, list_conf);
 
 
 	return ide_config_drive_speed(drive, speed);
 	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)
 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	= 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);
 	u8 drive_fast	= 0, drive_pci = 0x40 + (drive->dn * 4);
 	u32 list_conf	= 0, drive_conf = 0;
 	u32 list_conf	= 0, drive_conf = 0;
 	u32 conf_mask	= (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
 	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);
 	pci_read_config_byte(dev, regfast, &drive_fast);
 	drive_fast &= ~0x07;
 	drive_fast &= ~0x07;
 	pci_write_config_byte(dev, regfast, drive_fast);
 	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);
 	pci_read_config_dword(dev, drive_pci, &drive_conf);
 	list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
 	list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
 	if (speed < XFER_MW_DMA_0)
 	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)
 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 */
 		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);
 		return hpt372_tune_chipset(drive, speed);
-	else if (hpt_minimum_revision(dev, 3))
+	else if (info->revision >= 3)
 		return hpt370_tune_chipset(drive, speed);
 		return hpt370_tune_chipset(drive, speed);
 	else	/* hpt368: hpt_minimum_revision(dev, 2) */
 	else	/* hpt368: hpt_minimum_revision(dev, 2) */
 		return hpt36x_tune_chipset(drive, speed);
 		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)
 static int config_chipset_for_dma (ide_drive_t *drive)
 {
 {
 	u8 speed = ide_dma_speed(drive, hpt3xx_ratemask(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;
 		return 0;
 
 
 	(void) hpt3xx_tune_chipset(drive, speed);
 	(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)
 static void hpt3xx_intrproc (ide_drive_t *drive)
 {
 {
-	ide_hwif_t *hwif = HWIF(drive);
+	ide_hwif_t *hwif = drive->hwif;
 
 
 	if (drive->quirk_list)
 	if (drive->quirk_list)
 		return;
 		return;
@@ -804,24 +784,26 @@ static void hpt3xx_intrproc (ide_drive_t *drive)
 
 
 static void hpt3xx_maskproc (ide_drive_t *drive, int mask)
 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 (drive->quirk_list) {
-		if (hpt_minimum_revision(dev,3)) {
+		if (info->revision >= 3) {
 			u8 reg5a = 0;
 			u8 reg5a = 0;
 			pci_read_config_byte(dev, 0x5a, &reg5a);
 			pci_read_config_byte(dev, 0x5a, &reg5a);
 			if (((reg5a & 0x10) >> 4) != mask)
 			if (((reg5a & 0x10) >> 4) != mask)
 				pci_write_config_byte(dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
 				pci_write_config_byte(dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
 		} else {
 		} else {
 			if (mask) {
 			if (mask) {
-				disable_irq(HWIF(drive)->irq);
+				disable_irq(hwif->irq);
 			} else {
 			} else {
-				enable_irq(HWIF(drive)->irq);
+				enable_irq(hwif->irq);
 			}
 			}
 		}
 		}
 	} else {
 	} else {
 		if (IDE_CONTROL_REG)
 		if (IDE_CONTROL_REG)
-			HWIF(drive)->OUTB(mask ? (drive->ctl | 2) :
+			hwif->OUTB(mask ? (drive->ctl | 2) :
 						 (drive->ctl & ~2),
 						 (drive->ctl & ~2),
 						 IDE_CONTROL_REG);
 						 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)
 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;
 	struct hd_driveid *id	= drive->id;
 
 
 	drive->init_speed = 0;
 	drive->init_speed = 0;
 
 
-	if (id && (id->capability & 1) && drive->autodma) {
+	if ((id->capability & 1) && drive->autodma) {
 
 
 		if (ide_use_dma(drive)) {
 		if (ide_use_dma(drive)) {
 			if (config_chipset_for_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);
 		drive->name, __FUNCTION__, reg50h, reg52h, reg5ah);
 	if (reg5ah & 0x10)
 	if (reg5ah & 0x10)
 		pci_write_config_byte(dev, 0x5a, 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);
 	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;
 	u8 dma_stat = 0, dma_cmd = 0;
 
 
 	pci_read_config_byte(HWIF(drive)->pci_dev, reginfo, &bfifo);
 	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);
 	hpt370_clear_engine(drive);
 	/* get dma command mode */
 	/* get dma command mode */
 	dma_cmd = hwif->INB(hwif->dma_command);
 	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)
 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)
 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 reg59h = 0, reset	= (hwif->channel) ? 0x80 : 0x40;
 	u8 regXXh = 0, state_reg= (hwif->channel) ? 0x57 : 0x53;
 	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, 0x59, &reg59h);
 	pci_read_config_byte(dev, state_reg, &regXXh);
 	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
 #define TRISTATE_BIT  0x8000
 static int hpt370_busproc(ide_drive_t * drive, int state)
 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;
 	struct pci_dev *dev	= hwif->pci_dev;
 	u8 tristate = 0, resetmask = 0, bus_reg = 0;
 	u8 tristate = 0, resetmask = 0, bus_reg = 0;
 	u16 tri_reg;
 	u16 tri_reg;
@@ -1148,33 +1110,44 @@ static int hpt370_busproc(ide_drive_t * drive, int state)
 	return 0;
 	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;
 	int adjust, i;
 	u16 freq;
 	u16 freq;
 	u32 pll;
 	u32 pll;
 	u8 reg5bh;
 	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
 	 * 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);
 	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
 	 * 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");
 		printk(KERN_INFO "hpt: HPT372N detected, using 372N timing.\n");
 		if(freq < 0x55)
 		if(freq < 0x55)
@@ -1227,39 +1198,38 @@ static int __devinit init_hpt37x(struct pci_dev *dev)
 			pll = F_LOW_PCI_66;
 			pll = F_LOW_PCI_66;
 	
 	
 		if (pll == F_LOW_PCI_33) {
 		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
 			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) {
 		} else if (pll == F_LOW_PCI_40) {
 			/* Unsupported */
 			/* Unsupported */
 		} else if (pll == F_LOW_PCI_50) {
 		} 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
 			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 {
 		} else {
-			if (hpt_minimum_revision(dev,8))
-			{
+			if (info->revision >= 8) {
 				printk(KERN_ERR "HPT37x: 66MHz timings are not supported.\n");
 				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
 			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
 	 * result in slow reads when using a 33MHz PCI clock. we also
 	 * don't like to use the PLL because it will cause glitches
 	 * don't like to use the PLL because it will cause glitches
 	 * on PRST/SRST when the HPT state engine gets reset.
 	 * 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;
 		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
 	 * adjust PLL based upon PCI clock, enable it, and wait for
 	 * stabilization.
 	 * stabilization.
 	 */
 	 */
@@ -1298,14 +1276,14 @@ static int __devinit init_hpt37x(struct pci_dev *dev)
 				pci_write_config_dword(dev, 0x5c, 
 				pci_write_config_dword(dev, 0x5c, 
 						       pll & ~0x100);
 						       pll & ~0x100);
 				pci_write_config_byte(dev, 0x5b, 0x21);
 				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
 				else
-					pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+					info->speed = fifty_base_hpt370a;
 				printk("HPT37X: using 50MHz internal PLL\n");
 				printk("HPT37X: using 50MHz internal PLL\n");
 				goto init_hpt37X_done;
 				goto init_hpt37X_done;
 			}
 			}
@@ -1318,10 +1296,22 @@ pll_recal:
 	} 
 	} 
 
 
 init_hpt37X_done:
 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 */
 	/* reset state engine */
 	pci_write_config_byte(dev, 0x50, 0x37); 
 	pci_write_config_byte(dev, 0x50, 0x37); 
 	pci_write_config_byte(dev, 0x54, 0x37); 
 	pci_write_config_byte(dev, 0x54, 0x37); 
 	udelay(100);
 	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;
 	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_write_config_byte(dev, 0x51, drive_fast & ~0x80);
 	pci_read_config_dword(dev, 0x40, &reg1);
 	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;
 	return 0;
 }
 }
 
 
 static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const char *name)
 static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const char *name)
 {
 {
 	int ret = 0;
 	int ret = 0;
-	u8 test = 0;
-
+	/* FIXME: Not portable */
 	if (dev->resource[PCI_ROM_RESOURCE].start)
 	if (dev->resource[PCI_ROM_RESOURCE].start)
 		pci_write_config_byte(dev, PCI_ROM_ADDRESS,
 		pci_write_config_byte(dev, PCI_ROM_ADDRESS,
 			dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
 			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);
 		ret = init_hpt37x(dev);
-	} else {
-		ret =init_hpt366(dev);
-	}
+	else
+		ret = init_hpt366(dev);
+
 	if (ret)
 	if (ret)
 		return 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)
 static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
 {
 {
 	struct pci_dev *dev		= hwif->pci_dev;
 	struct pci_dev *dev		= hwif->pci_dev;
+	struct hpt_info *info		= ide_get_hwifdata(hwif);
 	u8 ata66 = 0, regmask		= (hwif->channel) ? 0x01 : 0x02;
 	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->tuneproc			= &hpt3xx_tune_drive;
 	hwif->speedproc			= &hpt3xx_tune_chipset;
 	hwif->speedproc			= &hpt3xx_tune_chipset;
 	hwif->quirkproc			= &hpt3xx_quirkproc;
 	hwif->quirkproc			= &hpt3xx_quirkproc;
 	hwif->intrproc			= &hpt3xx_intrproc;
 	hwif->intrproc			= &hpt3xx_intrproc;
 	hwif->maskproc			= &hpt3xx_maskproc;
 	hwif->maskproc			= &hpt3xx_maskproc;
 	
 	
-	if(is_372n)
+	if(info->flags & IS_372N)
 		hwif->rw_disk = &hpt372n_rw_disk;
 		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
 	 * address lines to access an external eeprom.  To read valid
 	 * cable detect state the pins must be enabled as inputs.
 	 * 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
 		 * HPT374 PCI function 1
 		 * - set bit 15 of reg 0x52 to enable TCBLID as input
 		 * - 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_read_config_byte(dev, 0x5a, &ata66);
 		pci_write_config_word(dev, 0x52, mcr3);
 		pci_write_config_word(dev, 0x52, mcr3);
 		pci_write_config_word(dev, 0x56, mcr6);
 		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
 		 * HPT370/372 and 374 pcifn 0
 		 * - clear bit 0 of 0x5b to enable P/SCBLID as inputs
 		 * - 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;
 		hwif->serialized = hwif->mate->serialized = 1;
 #endif
 #endif
 
 
-	if (hpt_minimum_revision(dev,3)) {
+	if (info->revision >= 3) {
 		u8 reg5ah = 0;
 		u8 reg5ah = 0;
 			pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
 			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->resetproc	= &hpt3xx_reset;
 		hwif->busproc	= &hpt370_busproc;
 		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->resetproc	= &hpt3xx_reset;
 		hwif->busproc	= &hpt3xx_tristate;
 		hwif->busproc	= &hpt3xx_tristate;
 	} else {
 	} else {
@@ -1502,18 +1448,18 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
 		hwif->udma_four = ((ata66 & regmask) ? 0 : 1);
 		hwif->udma_four = ((ata66 & regmask) ? 0 : 1);
 	hwif->ide_dma_check = &hpt366_config_drive_xfer_rate;
 	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_test_irq = &hpt374_ide_dma_test_irq;
 		hwif->ide_dma_end = &hpt374_ide_dma_end;
 		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_test_irq = &hpt374_ide_dma_test_irq;
 		hwif->ide_dma_end = &hpt374_ide_dma_end;
 		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->dma_start = &hpt370_ide_dma_start;
 		hwif->ide_dma_end = &hpt370_ide_dma_end;
 		hwif->ide_dma_end = &hpt370_ide_dma_end;
 		hwif->ide_dma_timeout = &hpt370_ide_dma_timeout;
 		hwif->ide_dma_timeout = &hpt370_ide_dma_timeout;
 		hwif->ide_dma_lostirq = &hpt370_ide_dma_lostirq;
 		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;
 		hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
 	else
 	else
 		hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
 		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)
 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 masterdma	= 0, slavedma = 0;
 	u8 dma_new	= 0, dma_old = 0;
 	u8 dma_new	= 0, dma_old = 0;
 	u8 primary	= hwif->channel ? 0x4b : 0x43;
 	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)
 	if (!dmabase)
 		return;
 		return;
 		
 		
-	if(pci_get_drvdata(hwif->pci_dev) == NULL)
-	{
+	if(info->speed == NULL) {
 		printk(KERN_WARNING "hpt: no known IDE timings, disabling DMA.\n");
 		printk(KERN_WARNING "hpt: no known IDE timings, disabling DMA.\n");
 		return;
 		return;
 	}
 	}
@@ -1559,6 +1505,40 @@ static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
 	ide_setup_dma(hwif, dmabase, 8);
 	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)
 static int __devinit init_setup_hpt374(struct pci_dev *dev, ide_pci_device_t *d)
 {
 {
 	struct pci_dev *findev = NULL;
 	struct pci_dev *findev = NULL;
@@ -1646,6 +1626,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
 		.name		= "HPT366",
 		.name		= "HPT366",
 		.init_setup	= init_setup_hpt366,
 		.init_setup	= init_setup_hpt366,
 		.init_chipset	= init_chipset_hpt366,
 		.init_chipset	= init_chipset_hpt366,
+		.init_iops	= init_iops_hpt366,
 		.init_hwif	= init_hwif_hpt366,
 		.init_hwif	= init_hwif_hpt366,
 		.init_dma	= init_dma_hpt366,
 		.init_dma	= init_dma_hpt366,
 		.channels	= 2,
 		.channels	= 2,
@@ -1656,6 +1637,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
 		.name		= "HPT372A",
 		.name		= "HPT372A",
 		.init_setup	= init_setup_hpt37x,
 		.init_setup	= init_setup_hpt37x,
 		.init_chipset	= init_chipset_hpt366,
 		.init_chipset	= init_chipset_hpt366,
+		.init_iops	= init_iops_hpt366,
 		.init_hwif	= init_hwif_hpt366,
 		.init_hwif	= init_hwif_hpt366,
 		.init_dma	= init_dma_hpt366,
 		.init_dma	= init_dma_hpt366,
 		.channels	= 2,
 		.channels	= 2,
@@ -1665,6 +1647,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
 		.name		= "HPT302",
 		.name		= "HPT302",
 		.init_setup	= init_setup_hpt37x,
 		.init_setup	= init_setup_hpt37x,
 		.init_chipset	= init_chipset_hpt366,
 		.init_chipset	= init_chipset_hpt366,
+		.init_iops	= init_iops_hpt366,
 		.init_hwif	= init_hwif_hpt366,
 		.init_hwif	= init_hwif_hpt366,
 		.init_dma	= init_dma_hpt366,
 		.init_dma	= init_dma_hpt366,
 		.channels	= 2,
 		.channels	= 2,
@@ -1674,6 +1657,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
 		.name		= "HPT371",
 		.name		= "HPT371",
 		.init_setup	= init_setup_hpt37x,
 		.init_setup	= init_setup_hpt37x,
 		.init_chipset	= init_chipset_hpt366,
 		.init_chipset	= init_chipset_hpt366,
+		.init_iops	= init_iops_hpt366,
 		.init_hwif	= init_hwif_hpt366,
 		.init_hwif	= init_hwif_hpt366,
 		.init_dma	= init_dma_hpt366,
 		.init_dma	= init_dma_hpt366,
 		.channels	= 2,
 		.channels	= 2,
@@ -1683,6 +1667,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
 		.name		= "HPT374",
 		.name		= "HPT374",
 		.init_setup	= init_setup_hpt374,
 		.init_setup	= init_setup_hpt374,
 		.init_chipset	= init_chipset_hpt366,
 		.init_chipset	= init_chipset_hpt366,
+		.init_iops	= init_iops_hpt366,
 		.init_hwif	= init_hwif_hpt366,
 		.init_hwif	= init_hwif_hpt366,
 		.init_dma	= init_dma_hpt366,
 		.init_dma	= init_dma_hpt366,
 		.channels	= 2,	/* 4 */
 		.channels	= 2,	/* 4 */
@@ -1692,6 +1677,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
 		.name		= "HPT372N",
 		.name		= "HPT372N",
 		.init_setup	= init_setup_hpt37x,
 		.init_setup	= init_setup_hpt37x,
 		.init_chipset	= init_chipset_hpt366,
 		.init_chipset	= init_chipset_hpt366,
+		.init_iops	= init_iops_hpt366,
 		.init_hwif	= init_hwif_hpt366,
 		.init_hwif	= init_hwif_hpt366,
 		.init_dma	= init_dma_hpt366,
 		.init_dma	= init_dma_hpt366,
 		.channels	= 2,	/* 4 */
 		.channels	= 2,	/* 4 */

+ 812 - 0
drivers/ide/pci/it821x.c

@@ -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");

+ 5 - 5
drivers/ide/pci/serverworks.c

@@ -442,7 +442,7 @@ static unsigned int __devinit init_chipset_svwks (struct pci_dev *dev, const cha
 	return (dev->irq) ? dev->irq : 0;
 	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;
 	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 clear = primary IDE channel does not have 80-pin cable.
  * Bit 14 set   = primary IDE channel has 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;
 	struct pci_dev *dev = hwif->pci_dev;
 	if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
 	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!
  * 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;
 	struct pci_dev *dev = hwif->pci_dev;
 	if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN &&
 	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;
 	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;
 	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);
 	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)) {
 	if (!(PCI_FUNC(dev->devfn) & 1)) {
 		d->bootable = NEVER_BOARD;
 		d->bootable = NEVER_BOARD;

+ 12 - 19
drivers/input/gameport/gameport.c

@@ -17,11 +17,10 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/gameport.h>
 #include <linux/gameport.h>
 #include <linux/wait.h>
 #include <linux/wait.h>
-#include <linux/completion.h>
 #include <linux/sched.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
+#include <linux/kthread.h>
 
 
 /*#include <asm/io.h>*/
 /*#include <asm/io.h>*/
 
 
@@ -238,8 +237,7 @@ struct gameport_event {
 static DEFINE_SPINLOCK(gameport_event_lock);	/* protects gameport_event_list */
 static DEFINE_SPINLOCK(gameport_event_lock);	/* protects gameport_event_list */
 static LIST_HEAD(gameport_event_list);
 static LIST_HEAD(gameport_event_list);
 static DECLARE_WAIT_QUEUE_HEAD(gameport_wait);
 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,
 static void gameport_queue_event(void *object, struct module *owner,
 			      enum gameport_event_type event_type)
 			      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);
 	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
 	 * 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
 	 * do not need add new one. If event is of different type we
 	 * need to add this event and should not look further because
 	 * need to add this event and should not look further because
 	 * we need to preseve sequence of distinct events.
 	 * we need to preseve sequence of distinct events.
- 	 */
+	 */
 	list_for_each_entry_reverse(event, &gameport_event_list, node) {
 	list_for_each_entry_reverse(event, &gameport_event_list, node) {
 		if (event->object == object) {
 		if (event->object == object) {
 			if (event->type == event_type)
 			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)
 static int gameport_thread(void *nothing)
 {
 {
-	lock_kernel();
-	daemonize("kgameportd");
-	allow_signal(SIGTERM);
-
 	do {
 	do {
 		gameport_handle_events();
 		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();
 		try_to_freeze();
-	} while (!signal_pending(current));
+	} while (!kthread_should_stop());
 
 
 	printk(KERN_DEBUG "gameport: kgameportd exiting\n");
 	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)
 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");
 		printk(KERN_ERR "gameport: Failed to start kgameportd\n");
-		return -1;
+		return PTR_ERR(gameport_task);
 	}
 	}
 
 
 	gameport_bus.dev_attrs = gameport_device_attrs;
 	gameport_bus.dev_attrs = gameport_device_attrs;
@@ -789,8 +783,7 @@ static int __init gameport_init(void)
 static void __exit gameport_exit(void)
 static void __exit gameport_exit(void)
 {
 {
 	bus_unregister(&gameport_bus);
 	bus_unregister(&gameport_bus);
-	kill_proc(gameport_pid, SIGTERM, 1);
-	wait_for_completion(&gameport_exited);
+	kthread_stop(gameport_task);
 }
 }
 
 
 module_init(gameport_init);
 module_init(gameport_init);

+ 62 - 27
drivers/input/serio/serio.c

@@ -31,10 +31,9 @@
 #include <linux/serio.h>
 #include <linux/serio.h>
 #include <linux/errno.h>
 #include <linux/errno.h>
 #include <linux/wait.h>
 #include <linux/wait.h>
-#include <linux/completion.h>
 #include <linux/sched.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
+#include <linux/kthread.h>
 
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("Serio abstraction core");
 MODULE_DESCRIPTION("Serio abstraction core");
@@ -43,6 +42,7 @@ MODULE_LICENSE("GPL");
 EXPORT_SYMBOL(serio_interrupt);
 EXPORT_SYMBOL(serio_interrupt);
 EXPORT_SYMBOL(__serio_register_port);
 EXPORT_SYMBOL(__serio_register_port);
 EXPORT_SYMBOL(serio_unregister_port);
 EXPORT_SYMBOL(serio_unregister_port);
+EXPORT_SYMBOL(serio_unregister_child_port);
 EXPORT_SYMBOL(__serio_unregister_port_delayed);
 EXPORT_SYMBOL(__serio_unregister_port_delayed);
 EXPORT_SYMBOL(__serio_register_driver);
 EXPORT_SYMBOL(__serio_register_driver);
 EXPORT_SYMBOL(serio_unregister_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_reconnect_port(struct serio *serio);
 static void serio_disconnect_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)
 static int serio_match_port(const struct serio_device_id *ids, struct serio *serio)
 {
 {
 	while (ids->type || ids->proto) {
 	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)) {
 	if (serio_match_port(drv->id_table, serio)) {
 		serio->dev.driver = &drv->driver;
 		serio->dev.driver = &drv->driver;
-		if (drv->connect(serio, drv)) {
+		if (serio_connect_driver(serio, drv)) {
 			serio->dev.driver = NULL;
 			serio->dev.driver = NULL;
 			goto out;
 			goto out;
 		}
 		}
@@ -138,8 +169,7 @@ struct serio_event {
 static DEFINE_SPINLOCK(serio_event_lock);	/* protects serio_event_list */
 static DEFINE_SPINLOCK(serio_event_lock);	/* protects serio_event_list */
 static LIST_HEAD(serio_event_list);
 static LIST_HEAD(serio_event_list);
 static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
 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,
 static void serio_queue_event(void *object, struct module *owner,
 			      enum serio_event_type event_type)
 			      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);
 	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
 	 * 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
 	 * do not need add new one. If event is of different type we
 	 * need to add this event and should not look further because
 	 * need to add this event and should not look further because
 	 * we need to preseve sequence of distinct events.
 	 * we need to preseve sequence of distinct events.
- 	 */
+	 */
 	list_for_each_entry_reverse(event, &serio_event_list, node) {
 	list_for_each_entry_reverse(event, &serio_event_list, node) {
 		if (event->object == object) {
 		if (event->object == object) {
 			if (event->type == event_type)
 			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)
 static int serio_thread(void *nothing)
 {
 {
-	lock_kernel();
-	daemonize("kseriod");
-	allow_signal(SIGTERM);
-
 	do {
 	do {
 		serio_handle_events();
 		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();
 		try_to_freeze();
-	} while (!signal_pending(current));
+	} while (!kthread_should_stop());
 
 
 	printk(KERN_DEBUG "serio: kseriod exiting\n");
 	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)
 static void serio_reconnect_port(struct serio *serio)
 {
 {
 	do {
 	do {
-		if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) {
+		if (serio_reconnect_driver(serio)) {
 			serio_disconnect_port(serio);
 			serio_disconnect_port(serio);
 			serio_find_driver(serio);
 			serio_find_driver(serio);
 			/* Ok, old children are now gone, we are done */
 			/* Ok, old children are now gone, we are done */
@@ -629,6 +654,19 @@ void serio_unregister_port(struct serio *serio)
 	up(&serio_sem);
 	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.
  * Submits register request to kseriod for subsequent execution.
  * Can be used when it is not obvious whether the serio_sem is
  * 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 *serio = to_serio_port(dev);
 	struct serio_driver *drv = to_serio_driver(dev->driver);
 	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)
 static int serio_driver_remove(struct device *dev)
 {
 {
 	struct serio *serio = to_serio_port(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;
 	return 0;
 }
 }
 
 
@@ -730,11 +767,9 @@ start_over:
 
 
 static void serio_set_drv(struct serio *serio, struct serio_driver *drv)
 static void serio_set_drv(struct serio *serio, struct serio_driver *drv)
 {
 {
-	down(&serio->drv_sem);
 	serio_pause_rx(serio);
 	serio_pause_rx(serio);
 	serio->drv = drv;
 	serio->drv = drv;
 	serio_continue_rx(serio);
 	serio_continue_rx(serio);
-	up(&serio->drv_sem);
 }
 }
 
 
 static int serio_bus_match(struct device *dev, struct device_driver *drv)
 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);
 	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
 		 * Driver re-probing can take a while, so better let kseriod
 		 * deal with it.
 		 * deal with it.
@@ -848,9 +883,10 @@ irqreturn_t serio_interrupt(struct serio *serio,
 
 
 static int __init serio_init(void)
 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");
 		printk(KERN_ERR "serio: Failed to start kseriod\n");
-		return -1;
+		return PTR_ERR(serio_task);
 	}
 	}
 
 
 	serio_bus.dev_attrs = serio_device_attrs;
 	serio_bus.dev_attrs = serio_device_attrs;
@@ -866,8 +902,7 @@ static int __init serio_init(void)
 static void __exit serio_exit(void)
 static void __exit serio_exit(void)
 {
 {
 	bus_unregister(&serio_bus);
 	bus_unregister(&serio_bus);
-	kill_proc(serio_pid, SIGTERM, 1);
-	wait_for_completion(&serio_exited);
+	kthread_stop(serio_task);
 }
 }
 
 
 module_init(serio_init);
 module_init(serio_init);

+ 9 - 0
drivers/isdn/hardware/avm/avm_cs.c

@@ -486,6 +486,14 @@ static int avmcs_event(event_t event, int priority,
     return 0;
     return 0;
 } /* avmcs_event */
 } /* 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 = {
 static struct pcmcia_driver avmcs_driver = {
 	.owner	= THIS_MODULE,
 	.owner	= THIS_MODULE,
 	.drv	= {
 	.drv	= {
@@ -493,6 +501,7 @@ static struct pcmcia_driver avmcs_driver = {
 	},
 	},
 	.attach	= avmcs_attach,
 	.attach	= avmcs_attach,
 	.detach	= avmcs_detach,
 	.detach	= avmcs_detach,
+	.id_table = avmcs_ids,
 };
 };
 
 
 static int __init avmcs_init(void)
 static int __init avmcs_init(void)

+ 8 - 0
drivers/isdn/hisax/avma1_cs.c

@@ -501,6 +501,13 @@ static int avma1cs_event(event_t event, int priority,
     return 0;
     return 0;
 } /* avma1cs_event */
 } /* 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 = {
 static struct pcmcia_driver avma1cs_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -508,6 +515,7 @@ static struct pcmcia_driver avma1cs_driver = {
 	},
 	},
 	.attach		= avma1cs_attach,
 	.attach		= avma1cs_attach,
 	.detach		= avma1cs_detach,
 	.detach		= avma1cs_detach,
+	.id_table	= avma1cs_ids,
 };
 };
  
  
 /*====================================================================*/
 /*====================================================================*/

+ 8 - 0
drivers/isdn/hisax/elsa_cs.c

@@ -508,6 +508,13 @@ static int elsa_cs_event(event_t event, int priority,
     return 0;
     return 0;
 } /* elsa_cs_event */
 } /* 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 = {
 static struct pcmcia_driver elsa_cs_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -515,6 +522,7 @@ static struct pcmcia_driver elsa_cs_driver = {
 	},
 	},
 	.attach		= elsa_cs_attach,
 	.attach		= elsa_cs_attach,
 	.detach		= elsa_cs_detach,
 	.detach		= elsa_cs_detach,
+	.id_table	= elsa_ids,
 };
 };
 
 
 static int __init init_elsa_cs(void)
 static int __init init_elsa_cs(void)

+ 13 - 0
drivers/isdn/hisax/sedlbauer_cs.c

@@ -616,6 +616,18 @@ static int sedlbauer_event(event_t event, int priority,
     return 0;
     return 0;
 } /* sedlbauer_event */
 } /* 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 = {
 static struct pcmcia_driver sedlbauer_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -623,6 +635,7 @@ static struct pcmcia_driver sedlbauer_driver = {
 	},
 	},
 	.attach		= sedlbauer_attach,
 	.attach		= sedlbauer_attach,
 	.detach		= sedlbauer_detach,
 	.detach		= sedlbauer_detach,
+	.id_table	= sedlbauer_ids,
 };
 };
 
 
 static int __init init_sedlbauer_cs(void)
 static int __init init_sedlbauer_cs(void)

+ 7 - 0
drivers/isdn/hisax/teles_cs.c

@@ -489,6 +489,12 @@ static int teles_cs_event(event_t event, int priority,
     return 0;
     return 0;
 } /* teles_cs_event */
 } /* 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 = {
 static struct pcmcia_driver teles_cs_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -496,6 +502,7 @@ static struct pcmcia_driver teles_cs_driver = {
 	},
 	},
 	.attach		= teles_attach,
 	.attach		= teles_attach,
 	.detach		= teles_detach,
 	.detach		= teles_detach,
+	.id_table       = teles_ids,
 };
 };
 
 
 static int __init init_teles_cs(void)
 static int __init init_teles_cs(void)

+ 10 - 0
drivers/mtd/maps/Kconfig

@@ -607,6 +607,16 @@ config MTD_PCMCIA
 	  cards are usually around 4-16MiB in size. This does not include
 	  cards are usually around 4-16MiB in size. This does not include
 	  Compact Flash cards which are treated as IDE devices.
 	  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
 config MTD_UCLINUX
 	tristate "Generic uClinux RAM/ROM filesystem support"
 	tristate "Generic uClinux RAM/ROM filesystem support"
 	depends on MTD_PARTITIONS && !MMU
 	depends on MTD_PARTITIONS && !MMU

+ 28 - 1
drivers/mtd/maps/pcmciamtd.c

@@ -818,6 +818,32 @@ static dev_link_t *pcmciamtd_attach(void)
 	return link;
 	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 = {
 static struct pcmcia_driver pcmciamtd_driver = {
 	.drv		= {
 	.drv		= {
@@ -825,7 +851,8 @@ static struct pcmcia_driver pcmciamtd_driver = {
 	},
 	},
 	.attach		= pcmciamtd_attach,
 	.attach		= pcmciamtd_attach,
 	.detach		= pcmciamtd_detach,
 	.detach		= pcmciamtd_detach,
-	.owner		= THIS_MODULE
+	.owner		= THIS_MODULE,
+	.id_table	= pcmciamtd_ids,
 };
 };
 
 
 
 

+ 8 - 0
drivers/net/pcmcia/3c574_cs.c

@@ -1286,6 +1286,13 @@ static int el3_close(struct net_device *dev)
 	return 0;
 	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 = {
 static struct pcmcia_driver tc574_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -1293,6 +1300,7 @@ static struct pcmcia_driver tc574_driver = {
 	},
 	},
 	.attach		= tc574_attach,
 	.attach		= tc574_attach,
 	.detach		= tc574_detach,
 	.detach		= tc574_detach,
+	.id_table       = tc574_ids,
 };
 };
 
 
 static int __init init_tc574(void)
 static int __init init_tc574(void)

+ 12 - 0
drivers/net/pcmcia/3c589_cs.c

@@ -1057,6 +1057,17 @@ static int el3_close(struct net_device *dev)
     return 0;
     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 = {
 static struct pcmcia_driver tc589_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -1064,6 +1075,7 @@ static struct pcmcia_driver tc589_driver = {
 	},
 	},
 	.attach		= tc589_attach,
 	.attach		= tc589_attach,
 	.detach		= tc589_detach,
 	.detach		= tc589_detach,
+        .id_table       = tc589_ids,
 };
 };
 
 
 static int __init init_tc589(void)
 static int __init init_tc589(void)

+ 29 - 0
drivers/net/pcmcia/axnet_cs.c

@@ -850,6 +850,34 @@ static void block_output(struct net_device *dev, int count,
     outsw(nic_base + AXNET_DATAPORT, buf, count>>1);
     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 = {
 static struct pcmcia_driver axnet_cs_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -857,6 +885,7 @@ static struct pcmcia_driver axnet_cs_driver = {
 	},
 	},
 	.attach		= axnet_attach,
 	.attach		= axnet_attach,
 	.detach		= axnet_detach,
 	.detach		= axnet_detach,
+	.id_table       = axnet_ids,
 };
 };
 
 
 static int __init init_axnet_cs(void)
 static int __init init_axnet_cs(void)

+ 6 - 1
drivers/net/pcmcia/com20020_cs.c

@@ -483,7 +483,11 @@ static int com20020_event(event_t event, int priority,
     return 0;
     return 0;
 } /* com20020_event */
 } /* 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 = {
 static struct pcmcia_driver com20020_cs_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
@@ -492,6 +496,7 @@ static struct pcmcia_driver com20020_cs_driver = {
 	},
 	},
 	.attach		= com20020_attach,
 	.attach		= com20020_attach,
 	.detach		= com20020_detach,
 	.detach		= com20020_detach,
+	.id_table	= com20020_ids,
 };
 };
 
 
 static int __init init_com20020_cs(void)
 static int __init init_com20020_cs(void)

+ 29 - 1
drivers/net/pcmcia/fmvj18x_cs.c

@@ -435,7 +435,9 @@ static void fmvj18x_config(dev_link_t *link)
 		pcmcia_get_status(handle, &status);
 		pcmcia_get_status(handle, &status);
 		if (status.CardState & CS_EVENT_3VCARD)
 		if (status.CardState & CS_EVENT_3VCARD)
 		    link->conf.Vcc = 33; /* inserted in 3.3V slot */
 		    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 */
 		/* MultiFunction Card */
 		link->conf.ConfigBase = 0x800;
 		link->conf.ConfigBase = 0x800;
 		link->conf.ConfigIndex = 0x47;
 		link->conf.ConfigIndex = 0x47;
@@ -764,6 +766,31 @@ static int fmvj18x_event(event_t event, int priority,
     return 0;
     return 0;
 } /* fmvj18x_event */
 } /* 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 = {
 static struct pcmcia_driver fmvj18x_cs_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -771,6 +798,7 @@ static struct pcmcia_driver fmvj18x_cs_driver = {
 	},
 	},
 	.attach		= fmvj18x_attach,
 	.attach		= fmvj18x_attach,
 	.detach		= fmvj18x_detach,
 	.detach		= fmvj18x_detach,
+	.id_table       = fmvj18x_ids,
 };
 };
 
 
 static int __init init_fmvj18x_cs(void)
 static int __init init_fmvj18x_cs(void)

+ 8 - 0
drivers/net/pcmcia/ibmtr_cs.c

@@ -508,6 +508,13 @@ static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase)
     return;
     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 = {
 static struct pcmcia_driver ibmtr_cs_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -515,6 +522,7 @@ static struct pcmcia_driver ibmtr_cs_driver = {
 	},
 	},
 	.attach		= ibmtr_attach,
 	.attach		= ibmtr_attach,
 	.detach		= ibmtr_detach,
 	.detach		= ibmtr_detach,
+	.id_table       = ibmtr_ids,
 };
 };
 
 
 static int __init init_ibmtr_cs(void)
 static int __init init_ibmtr_cs(void)

+ 8 - 0
drivers/net/pcmcia/nmclan_cs.c

@@ -1675,6 +1675,13 @@ static void set_multicast_list(struct net_device *dev)
 
 
 } /* set_multicast_list */
 } /* 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 = {
 static struct pcmcia_driver nmclan_cs_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -1682,6 +1689,7 @@ static struct pcmcia_driver nmclan_cs_driver = {
 	},
 	},
 	.attach		= nmclan_attach,
 	.attach		= nmclan_attach,
 	.detach		= nmclan_detach,
 	.detach		= nmclan_detach,
+	.id_table       = nmclan_ids,
 };
 };
 
 
 static int __init init_nmclan_cs(void)
 static int __init init_nmclan_cs(void)

+ 203 - 0
drivers/net/pcmcia/pcnet_cs.c

@@ -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 = {
 static struct pcmcia_driver pcnet_driver = {
 	.drv		= {
 	.drv		= {
 		.name	= "pcnet_cs",
 		.name	= "pcnet_cs",
@@ -1644,6 +1846,7 @@ static struct pcmcia_driver pcnet_driver = {
 	.attach		= pcnet_attach,
 	.attach		= pcnet_attach,
 	.detach		= pcnet_detach,
 	.detach		= pcnet_detach,
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
+	.id_table	= pcnet_ids,
 };
 };
 
 
 static int __init init_pcnet_cs(void)
 static int __init init_pcnet_cs(void)

+ 33 - 0
drivers/net/pcmcia/smc91c92_cs.c

@@ -2327,6 +2327,38 @@ static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
 	return rc;
 	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 = {
 static struct pcmcia_driver smc91c92_cs_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -2334,6 +2366,7 @@ static struct pcmcia_driver smc91c92_cs_driver = {
 	},
 	},
 	.attach		= smc91c92_attach,
 	.attach		= smc91c92_attach,
 	.detach		= smc91c92_detach,
 	.detach		= smc91c92_detach,
+	.id_table       = smc91c92_ids,
 };
 };
 
 
 static int __init init_smc91c92_cs(void)
 static int __init init_smc91c92_cs(void)

+ 28 - 0
drivers/net/pcmcia/xirc2ps_cs.c

@@ -1983,6 +1983,33 @@ do_stop(struct net_device *dev)
     return 0;
     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 = {
 static struct pcmcia_driver xirc2ps_cs_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -1990,6 +2017,7 @@ static struct pcmcia_driver xirc2ps_cs_driver = {
 	},
 	},
 	.attach		= xirc2ps_attach,
 	.attach		= xirc2ps_attach,
 	.detach		= xirc2ps_detach,
 	.detach		= xirc2ps_detach,
+	.id_table       = xirc2ps_ids,
 };
 };
 
 
 static int __init
 static int __init

+ 10 - 0
drivers/net/wireless/airo_cs.c

@@ -559,6 +559,15 @@ static int airo_event(event_t event, int priority,
 	return 0;
 	return 0;
 } /* airo_event */
 } /* 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 = {
 static struct pcmcia_driver airo_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -566,6 +575,7 @@ static struct pcmcia_driver airo_driver = {
 	},
 	},
 	.attach		= airo_attach,
 	.attach		= airo_attach,
 	.detach		= airo_detach,
 	.detach		= airo_detach,
+	.id_table       = airo_ids,
 };
 };
 
 
 static int airo_cs_init(void)
 static int airo_cs_init(void)

+ 22 - 0
drivers/net/wireless/atmel_cs.c

@@ -646,6 +646,27 @@ static int atmel_event(event_t event, int priority,
 } /* atmel_event */
 } /* 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 = {
 static struct pcmcia_driver atmel_driver = {
         .owner          = THIS_MODULE,
         .owner          = THIS_MODULE,
         .drv            = {
         .drv            = {
@@ -653,6 +674,7 @@ static struct pcmcia_driver atmel_driver = {
         },
         },
         .attach         = atmel_attach,
         .attach         = atmel_attach,
         .detach         = atmel_detach,
         .detach         = atmel_detach,
+	.id_table	= atmel_ids,
 };
 };
 
 
 static int atmel_cs_init(void)
 static int atmel_cs_init(void)

+ 7 - 0
drivers/net/wireless/netwave_cs.c

@@ -1668,6 +1668,12 @@ static int netwave_close(struct net_device *dev) {
     return 0;
     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 = {
 static struct pcmcia_driver netwave_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -1675,6 +1681,7 @@ static struct pcmcia_driver netwave_driver = {
 	},
 	},
 	.attach		= netwave_attach,
 	.attach		= netwave_attach,
 	.detach		= netwave_detach,
 	.detach		= netwave_detach,
+	.id_table       = netwave_ids,
 };
 };
 
 
 static int __init init_netwave_cs(void)
 static int __init init_netwave_cs(void)

+ 51 - 0
drivers/net/wireless/orinoco_cs.c

@@ -608,6 +608,56 @@ static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
 	" (David Gibson <hermes@gibson.dropbear.id.au>, "
 	" (David Gibson <hermes@gibson.dropbear.id.au>, "
 	"Pavel Roskin <proski@gnu.org>, et al)";
 	"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 = {
 static struct pcmcia_driver orinoco_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -615,6 +665,7 @@ static struct pcmcia_driver orinoco_driver = {
 	},
 	},
 	.attach		= orinoco_cs_attach,
 	.attach		= orinoco_cs_attach,
 	.detach		= orinoco_cs_detach,
 	.detach		= orinoco_cs_detach,
+	.id_table       = orinoco_cs_ids,
 };
 };
 
 
 static int __init
 static int __init

+ 7 - 0
drivers/net/wireless/ray_cs.c

@@ -2904,6 +2904,12 @@ static int write_int(struct file *file, const char __user *buffer, unsigned long
 }
 }
 #endif
 #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 = {
 static struct pcmcia_driver ray_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -2911,6 +2917,7 @@ static struct pcmcia_driver ray_driver = {
 	},
 	},
 	.attach		= ray_attach,
 	.attach		= ray_attach,
 	.detach		= ray_detach,
 	.detach		= ray_detach,
+	.id_table       = ray_ids,
 };
 };
 
 
 static int __init init_ray_cs(void)
 static int __init init_ray_cs(void)

+ 10 - 0
drivers/net/wireless/wavelan_cs.c

@@ -4889,6 +4889,15 @@ wavelan_event(event_t		event,		/* The event received */
   return 0;
   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 = {
 static struct pcmcia_driver wavelan_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -4896,6 +4905,7 @@ static struct pcmcia_driver wavelan_driver = {
 	},
 	},
 	.attach		= wavelan_attach,
 	.attach		= wavelan_attach,
 	.detach		= wavelan_detach,
 	.detach		= wavelan_detach,
+	.id_table       = wavelan_ids,
 };
 };
 
 
 static int __init
 static int __init

+ 7 - 0
drivers/net/wireless/wl3501_cs.c

@@ -2239,6 +2239,12 @@ static int wl3501_event(event_t event, int pri, event_callback_args_t *args)
 	return 0;
 	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 = {
 static struct pcmcia_driver wl3501_driver = {
 	.owner          = THIS_MODULE,
 	.owner          = THIS_MODULE,
 	.drv            = {
 	.drv            = {
@@ -2246,6 +2252,7 @@ static struct pcmcia_driver wl3501_driver = {
 	},
 	},
 	.attach         = wl3501_attach,
 	.attach         = wl3501_attach,
 	.detach         = wl3501_detach,
 	.detach         = wl3501_detach,
+	.id_table	= wl3501_ids,
 };
 };
 
 
 static int __init wl3501_init_module(void)
 static int __init wl3501_init_module(void)

+ 9 - 0
drivers/parport/parport_cs.c

@@ -373,6 +373,13 @@ int parport_event(event_t event, int priority,
     return 0;
     return 0;
 } /* parport_event */
 } /* 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 = {
 static struct pcmcia_driver parport_cs_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -380,6 +387,8 @@ static struct pcmcia_driver parport_cs_driver = {
 	},
 	},
 	.attach		= parport_attach,
 	.attach		= parport_attach,
 	.detach		= parport_detach,
 	.detach		= parport_detach,
+	.id_table	= parport_ids,
+
 };
 };
 
 
 static int __init init_parport_cs(void)
 static int __init init_parport_cs(void)

+ 35 - 8
drivers/pcmcia/Kconfig

@@ -14,8 +14,8 @@ config PCCARD
 	  Say Y here if you want to attach PCMCIA- or PC-cards to your Linux
 	  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,
 	  computer.  These are credit-card size devices such as network cards,
 	  modems or hard drives often used with laptops computers.  There are
 	  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
 	  To compile this driver as modules, choose M here: the
 	  module will be called pcmcia_core.
 	  module will be called pcmcia_core.
@@ -42,22 +42,51 @@ config PCMCIA_DEBUG
 
 
 config PCMCIA
 config PCMCIA
 	tristate "16-bit PCMCIA support"
 	tristate "16-bit PCMCIA support"
+	select CRC32
 	default y
 	default y
 	---help---
 	---help---
 	   This option enables support for 16-bit PCMCIA cards. Most older
 	   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
 	   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.
 	   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
 	   To compile this driver as modules, choose M here: the
 	   module will be called pcmcia.
 	   module will be called pcmcia.
 
 
 	   If unsure, say Y.
 	   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
 config CARDBUS
 	bool "32-bit CardBus support"	
 	bool "32-bit CardBus support"	
 	depends on PCI
 	depends on PCI
@@ -77,8 +106,6 @@ comment "PC-card bridges"
 
 
 config YENTA
 config YENTA
 	tristate "CardBus yenta-compatible bridge support"
 	tristate "CardBus yenta-compatible bridge support"
-	depends on PCI
-#fixme: remove dependendcy on CARDBUS
 	depends on CARDBUS
 	depends on CARDBUS
 	select PCCARD_NONSTATIC
 	select PCCARD_NONSTATIC
 	---help---
 	---help---

+ 2 - 1
drivers/pcmcia/Makefile

@@ -10,7 +10,8 @@ pcmcia_core-y					+= cs.o cistpl.o rsrc_mgr.o socket_sysfs.o
 pcmcia_core-$(CONFIG_CARDBUS)			+= cardbus.o
 pcmcia_core-$(CONFIG_CARDBUS)			+= cardbus.o
 obj-$(CONFIG_PCCARD)				+= pcmcia_core.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_PCMCIA)				+= pcmcia.o
 
 
 obj-$(CONFIG_PCCARD_NONSTATIC)			+= rsrc_nonstatic.o
 obj-$(CONFIG_PCCARD_NONSTATIC)			+= rsrc_nonstatic.o

+ 20 - 8
drivers/pcmcia/cistpl.c

@@ -89,8 +89,10 @@ static void __iomem *
 set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flags)
 set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flags)
 {
 {
     pccard_mem_map *mem = &s->cis_mem;
     pccard_mem_map *mem = &s->cis_mem;
+    int ret;
+
     if (!(s->features & SS_CAP_STATIC_MAP) && mem->res == NULL) {
     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) {
 	if (mem->res == NULL) {
 	    printk(KERN_NOTICE "cs: unable to map card memory!\n");
 	    printk(KERN_NOTICE "cs: unable to map card memory!\n");
 	    return NULL;
 	    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->card_start = card_offset;
     mem->flags = flags;
     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->features & SS_CAP_STATIC_MAP) {
 	if (s->cis_virt)
 	if (s->cis_virt)
 	    iounmap(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_ATTR		1
 #define IS_INDIRECT	8
 #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)
 		 u_int len, void *ptr)
 {
 {
     void __iomem *sys, *end;
     void __iomem *sys, *end;
     unsigned char *buf = ptr;
     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) {
     if (attr & IS_INDIRECT) {
 	/* Indirect accesses use a bunch of special registers at fixed
 	/* 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));
 	  *(u_char *)(ptr+2), *(u_char *)(ptr+3));
     return 0;
     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)
 		   u_int len, void *ptr)
 {
 {
     void __iomem *sys, *end;
     void __iomem *sys, *end;
     unsigned char *buf = ptr;
     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) {
     if (attr & IS_INDIRECT) {
 	/* Indirect accesses use a bunch of special registers at fixed
 	/* 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);
 	ret = read_cb_mem(s, attr, addr, len, ptr);
     else
     else
 #endif
 #endif
-	ret = read_cis_mem(s, attr, addr, len, ptr);
+	ret = pcmcia_read_cis_mem(s, attr, addr, len, ptr);
 
 
 	if (ret == 0) {
 	if (ret == 0) {
 		/* Copy data into the cache */
 		/* 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);
 			read_cb_mem(s, cis->attr, cis->addr, len, buf);
 		else
 		else
 #endif
 #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) {
 		if (memcmp(buf, cis->cache, len) != 0) {
 			kfree(buf);
 			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);
     memcpy(s->fake_cis, cis->Data, cis->Length);
     return CS_SUCCESS;
     return CS_SUCCESS;
 }
 }
+EXPORT_SYMBOL(pcmcia_replace_cis);
 
 
 /*======================================================================
 /*======================================================================
 
 

+ 91 - 1073
drivers/pcmcia/cs.c

@@ -43,36 +43,11 @@
 #include <pcmcia/ds.h>
 #include <pcmcia/ds.h>
 #include "cs_internal.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 parameters */
 
 
 MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
 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");
 MODULE_LICENSE("GPL");
 
 
 #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444)
 #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 */
 /* Access speed for attribute memory windows */
 INT_MODULE_PARM(cis_speed,	300);		/* ns */
 INT_MODULE_PARM(cis_speed,	300);		/* ns */
 
 
-/* Access speed for IO windows */
-INT_MODULE_PARM(io_speed,	0);		/* ns */
-
 #ifdef DEBUG
 #ifdef DEBUG
 static int pc_debug;
 static int pc_debug;
 
 
@@ -103,34 +75,26 @@ int cs_debug_level(int level)
 }
 }
 #endif
 #endif
 
 
-/*====================================================================*/
 
 
 socket_state_t dead_socket = {
 socket_state_t dead_socket = {
 	.csc_mask	= SS_DETECT,
 	.csc_mask	= SS_DETECT,
 };
 };
+EXPORT_SYMBOL(dead_socket);
 
 
 
 
 /* List of all sockets, protected by a rwsem */
 /* List of all sockets, protected by a rwsem */
 LIST_HEAD(pcmcia_socket_list);
 LIST_HEAD(pcmcia_socket_list);
-DECLARE_RWSEM(pcmcia_socket_list_rwsem);
 EXPORT_SYMBOL(pcmcia_socket_list);
 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:
  * .drv struct:
  *  - pcmcia_socket_dev_suspend
  *  - pcmcia_socket_dev_suspend
  *  - pcmcia_socket_dev_resume
  *  - 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
 	/* 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] */
 	 * anyways, so I don't care] */
 	down_write(&pcmcia_socket_list_rwsem);
 	down_write(&pcmcia_socket_list_rwsem);
 	if (list_empty(&pcmcia_socket_list))
 	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);
 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)
 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
 #ifdef CONFIG_CARDBUS
-    cb_free(s);
+	cb_free(s);
 #endif
 #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. */
 /* 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);
 		wake_up(&s->thread_wait);
 	}
 	}
 } /* pcmcia_parse_events */
 } /* 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 */
 /* register pcmcia_callback */
 int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c)
 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);
 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 pccard_reset_card(struct pcmcia_socket *skt)
 {
 {
 	int ret;
 	int ret;
-    
+
 	cs_dbg(skt, 1, "resetting socket\n");
 	cs_dbg(skt, 1, "resetting socket\n");
 
 
 	down(&skt->skt_sem);
 	down(&skt->skt_sem);
@@ -1757,17 +778,14 @@ int pccard_reset_card(struct pcmcia_socket *skt)
 } /* reset_card */
 } /* reset_card */
 EXPORT_SYMBOL(pccard_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 pcmcia_suspend_card(struct pcmcia_socket *skt)
 {
 {
 	int ret;
 	int ret;
-    
+
 	cs_dbg(skt, 1, "suspending socket\n");
 	cs_dbg(skt, 1, "suspending socket\n");
 
 
 	down(&skt->skt_sem);
 	down(&skt->skt_sem);
@@ -1786,6 +804,8 @@ int pcmcia_suspend_card(struct pcmcia_socket *skt)
 
 
 	return ret;
 	return ret;
 } /* suspend_card */
 } /* suspend_card */
+EXPORT_SYMBOL(pcmcia_suspend_card);
+
 
 
 int pcmcia_resume_card(struct pcmcia_socket *skt)
 int pcmcia_resume_card(struct pcmcia_socket *skt)
 {
 {
@@ -1809,13 +829,10 @@ int pcmcia_resume_card(struct pcmcia_socket *skt)
 
 
 	return ret;
 	return ret;
 } /* resume_card */
 } /* 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 pcmcia_eject_card(struct pcmcia_socket *skt)
 {
 {
 	int ret;
 	int ret;
@@ -1842,6 +859,8 @@ int pcmcia_eject_card(struct pcmcia_socket *skt)
 
 
 	return ret;
 	return ret;
 } /* eject_card */
 } /* eject_card */
+EXPORT_SYMBOL(pcmcia_eject_card);
+
 
 
 int pcmcia_insert_card(struct pcmcia_socket *skt)
 int pcmcia_insert_card(struct pcmcia_socket *skt)
 {
 {
@@ -1865,37 +884,38 @@ int pcmcia_insert_card(struct pcmcia_socket *skt)
 
 
 	return ret;
 	return ret;
 } /* insert_card */
 } /* 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 = {
 struct class pcmcia_socket_class = {
 	.name = "pcmcia_socket",
 	.name = "pcmcia_socket",
+        .hotplug = pcmcia_socket_hotplug,
 	.release = pcmcia_release_socket,
 	.release = pcmcia_release_socket,
+	.class_release = pcmcia_release_socket_class,
 };
 };
 EXPORT_SYMBOL(pcmcia_socket_class);
 EXPORT_SYMBOL(pcmcia_socket_class);
 
 
@@ -1903,9 +923,8 @@ EXPORT_SYMBOL(pcmcia_socket_class);
 static int __init init_pcmcia_cs(void)
 static int __init init_pcmcia_cs(void)
 {
 {
 	int ret;
 	int ret;
-	printk(KERN_INFO "%s\n", release);
-	printk(KERN_INFO "  %s\n", options);
 
 
+	init_completion(&pcmcia_unload);
 	ret = class_register(&pcmcia_socket_class);
 	ret = class_register(&pcmcia_socket_class);
 	if (ret)
 	if (ret)
 		return (ret);
 		return (ret);
@@ -1914,13 +933,12 @@ static int __init init_pcmcia_cs(void)
 
 
 static void __exit exit_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);
 subsys_initcall(init_pcmcia_cs);
 module_exit(exit_pcmcia_cs);
 module_exit(exit_pcmcia_cs);
 
 
-/*====================================================================*/
-

+ 6 - 7
drivers/pcmcia/cs_internal.h

@@ -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);
 int read_cb_mem(struct pcmcia_socket *s, int space, u_int addr, u_int len, void *ptr);
 
 
 /* In cistpl.c */
 /* 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);
 		 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);
 		   u_int addr, u_int len, void *ptr);
 void release_cis_mem(struct pcmcia_socket *s);
 void release_cis_mem(struct pcmcia_socket *s);
 void destroy_cis_cache(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 */
 /* In rsrc_mgr */
 void pcmcia_validate_mem(struct pcmcia_socket *s);
 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);
 		   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);
 		     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 low, struct pcmcia_socket *s);
-int adjust_resource_info(client_handle_t handle, adjust_t *adj);
 void release_resource_db(struct pcmcia_socket *s);
 void release_resource_db(struct pcmcia_socket *s);
 
 
 /* In socket_sysfs.c */
 /* In socket_sysfs.c */
@@ -159,7 +158,7 @@ int pccard_access_configuration_register(struct pcmcia_socket *s, unsigned int f
 struct pcmcia_callback{
 struct pcmcia_callback{
 	struct module	*owner;
 	struct module	*owner;
 	int		(*event) (struct pcmcia_socket *s, event_t event, int priority);
 	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);
 int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c);

+ 420 - 835
drivers/pcmcia/ds.c

@@ -10,44 +10,29 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  *
  * (C) 1999		David A. Hinds
  * (C) 1999		David A. Hinds
- * (C) 2003 - 2004	Dominik Brodowski
+ * (C) 2003 - 2005	Dominik Brodowski
  */
  */
 
 
 #include <linux/config.h>
 #include <linux/config.h>
+#include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/string.h>
 #include <linux/errno.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/list.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
-#include <linux/kref.h>
 #include <linux/workqueue.h>
 #include <linux/workqueue.h>
-
-#include <asm/atomic.h>
+#include <linux/crc32.h>
+#include <linux/firmware.h>
 
 
 #define IN_CARD_SERVICES
 #define IN_CARD_SERVICES
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cs.h>
-#include <pcmcia/bulkmem.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 #include <pcmcia/ds.h>
 #include <pcmcia/ss.h>
 #include <pcmcia/ss.h>
 
 
 #include "cs_internal.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)
 #define ds_dbg(lvl, fmt, arg...) do { } while (0)
 #endif
 #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;
 	int i;
 	char *serv;
 	char *serv;
@@ -243,7 +188,6 @@ int pcmcia_report_error(client_handle_t handle, error_info_t *err)
 
 
 	return CS_SUCCESS;
 	return CS_SUCCESS;
 } /* report_error */
 } /* report_error */
-EXPORT_SYMBOL(pcmcia_report_error);
 
 
 /* end of code which was in cs.c before */
 /* 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);
 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
  * 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)
 	if (!driver)
 		return -EINVAL;
 		return -EINVAL;
 
 
+	pcmcia_check_driver(driver);
+
 	/* initialize common fields */
 	/* initialize common fields */
 	driver->drv.bus = &pcmcia_bus_type;
 	driver->drv.bus = &pcmcia_bus_type;
 	driver->drv.owner = driver->owner;
 	driver->drv.owner = driver->owner;
@@ -311,42 +329,10 @@ void pcmcia_unregister_driver(struct pcmcia_driver *driver)
 }
 }
 EXPORT_SYMBOL(pcmcia_unregister_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 */
 /* 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;
 	struct device *tmp_dev;
 	tmp_dev = get_device(&p_dev->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);
 	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)
 	if (p_dev)
 		put_device(&p_dev->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);
 	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
 	ds_dbg(1, "releasing dev %p\n", p_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);
 	kfree(p_dev);
 }
 }
 
 
@@ -500,34 +486,38 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev)
  */
  */
 static DECLARE_MUTEX(device_add_lock);
 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;
 	struct pcmcia_device *p_dev;
 	unsigned long flags;
 	unsigned long flags;
 
 
-	s = pcmcia_get_bus_socket(s);
+	s = pcmcia_get_socket(s);
 	if (!s)
 	if (!s)
 		return NULL;
 		return NULL;
 
 
 	down(&device_add_lock);
 	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);
 	p_dev = kmalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
 	if (!p_dev)
 	if (!p_dev)
 		goto err_put;
 		goto err_put;
 	memset(p_dev, 0, sizeof(struct pcmcia_device));
 	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->device_no = (s->device_count++);
 	p_dev->func   = function;
 	p_dev->func   = function;
 
 
 	p_dev->dev.bus = &pcmcia_bus_type;
 	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;
 	p_dev->dev.release = pcmcia_release_dev;
 	sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no);
 	sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no);
 
 
 	/* compat */
 	/* compat */
 	p_dev->client.client_magic = CLIENT_MAGIC;
 	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.Function = function;
 	p_dev->client.state = CLIENT_UNBOUND;
 	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);
 	list_add_tail(&p_dev->socket_device_list, &s->devices_list);
 	spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
 	spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
 
 
+	pcmcia_device_query(p_dev);
+
 	if (device_register(&p_dev->dev)) {
 	if (device_register(&p_dev->dev)) {
 		spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
 		spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
 		list_del(&p_dev->socket_device_list);
 		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--;
 	s->device_count--;
  err_put:
  err_put:
 	up(&device_add_lock);
 	up(&device_add_lock);
-	pcmcia_put_bus_socket(s);
+	pcmcia_put_socket(s);
 
 
 	return NULL;
 	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
 	/* this doesn't handle multifunction devices on one pcmcia function
 	 * yet. */
 	 * yet. */
 	for (i=0; i < no_funcs; i++)
 	for (i=0; i < no_funcs; i++)
-		pcmcia_device_add(s->pcmcia, i);
+		pcmcia_device_add(s, i);
 
 
 	return (ret);
 	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) {
 static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) {
 	struct pcmcia_device * p_dev = to_pcmcia_dev(dev);
 	struct pcmcia_device * p_dev = to_pcmcia_dev(dev);
 	struct pcmcia_driver * p_drv = to_pcmcia_drv(drv);
 	struct pcmcia_driver * p_drv = to_pcmcia_drv(drv);
+	struct pcmcia_device_id *did = p_drv->id_table;
 
 
 	/* matching by cardmgr */
 	/* matching by cardmgr */
 	if (p_dev->cardmgr == p_drv)
 	if (p_dev->cardmgr == p_drv)
 		return 1;
 		return 1;
 
 
+	while (did && did->match_flags) {
+		if (pcmcia_devmatch(p_dev, did))
+			return 1;
+		did++;
+	}
+
 	return 0;
 	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 ***************************/
 /************************ per-device sysfs output ***************************/
 
 
 #define pcmcia_device_attr(field, test, format)				\
 #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_id3, prod_id[2]);
 pcmcia_device_stringattr(prod_id4, prod_id[3]);
 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[] = {
 static struct device_attribute pcmcia_dev_attrs[] = {
 	__ATTR(function, 0444, func_show, NULL),
 	__ATTR(function, 0444, func_show, NULL),
 	__ATTR_RO(func_id),
 	__ATTR_RO(func_id),
@@ -635,44 +893,12 @@ static struct device_attribute pcmcia_dev_attrs[] = {
 	__ATTR_RO(prod_id2),
 	__ATTR_RO(prod_id2),
 	__ATTR_RO(prod_id3),
 	__ATTR_RO(prod_id3),
 	__ATTR_RO(prod_id4),
 	__ATTR_RO(prod_id4),
+	__ATTR_RO(modalias),
+	__ATTR(allow_func_id_match, 0200, NULL, pcmcia_store_allow_func_id_match),
 	__ATTR_NULL,
 	__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.
     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)
 static int send_event(struct pcmcia_socket *s, event_t event, int priority)
 {
 {
-	int ret = 0;
 	struct send_event_data private;
 	struct send_event_data private;
-	struct pcmcia_bus_socket *skt = pcmcia_get_bus_socket(s->pcmcia);
-
-	if (!skt)
-		return 0;
 
 
 	private.skt = s;
 	private.skt = s;
 	private.event = event;
 	private.event = event;
 	private.priority = priority;
 	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 */
 } /* 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)
 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;
 	int ret = 0;
 
 
 	ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n",
 	ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n",
-	       event, priority, s);
+	       event, priority, skt);
     
     
 	switch (event) {
 	switch (event) {
 
 
 	case CS_EVENT_CARD_REMOVAL:
 	case CS_EVENT_CARD_REMOVAL:
-		s->state &= ~DS_SOCKET_PRESENT;
+		s->pcmcia_state.present = 0;
 	    	send_event(skt, event, priority);
 	    	send_event(skt, event, priority);
-		unbind_request(s);
-		handle_event(s, event);
+		unbind_request(skt);
+		handle_event(skt, event);
 		break;
 		break;
 	
 	
 	case CS_EVENT_CARD_INSERTION:
 	case CS_EVENT_CARD_INSERTION:
-		s->state |= DS_SOCKET_PRESENT;
+		s->pcmcia_state.present = 1;
 		pcmcia_card_add(skt);
 		pcmcia_card_add(skt);
-		handle_event(s, event);
+		handle_event(skt, event);
 		break;
 		break;
 
 
 	case CS_EVENT_EJECTION_REQUEST:
 	case CS_EVENT_EJECTION_REQUEST:
@@ -757,137 +975,22 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
 		break;
 		break;
 
 
 	default:
 	default:
-		handle_event(s, event);
+		handle_event(skt, event);
 		send_event(skt, event, priority);
 		send_event(skt, event, priority);
 		break;
 		break;
     }
     }
 
 
+    pcmcia_put_socket(s);
+
     return 0;
     return 0;
 } /* ds_event */
 } /* 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)
 int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
 {
 {
 	client_t *client = NULL;
 	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;
 	struct pcmcia_device *p_dev = NULL;
 
 
 	/* Look for unbound client with matching dev_info */
 	/* 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)
 		if (s->state & SOCKET_CARDBUS)
 			continue;
 			continue;
 
 
-		skt = s->pcmcia;
-		if (!skt)
-			continue;
-		skt = pcmcia_get_bus_socket(skt);
-		if (!skt)
+		s = pcmcia_get_socket(s);
+		if (!s)
 			continue;
 			continue;
 		spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
 		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;
 			struct pcmcia_driver *p_drv;
 			p_dev = pcmcia_get_dev(p_dev);
 			p_dev = pcmcia_get_dev(p_dev);
 			if (!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);
 			pcmcia_put_dev(p_dev);
 		}
 		}
 		spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
 		spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
-		pcmcia_put_bus_socket(skt);
+		pcmcia_put_socket(s);
 	}
 	}
  found:
  found:
 	up_read(&pcmcia_socket_list_rwsem);
 	up_read(&pcmcia_socket_list_rwsem);
 	if (!p_dev || !client)
 	if (!p_dev || !client)
 		return -ENODEV;
 		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;
 	*handle = client;
 	client->state &= ~CLIENT_UNBOUND;
 	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);
 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
 /* unbind _all_ devices attached to a given pcmcia_bus_socket. The
  * drivers have been called with EVENT_CARD_REMOVAL before.
  * 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;
 	struct pcmcia_device	*p_dev;
 	unsigned long		flags;
 	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;
 	s->device_count = 0;
 
 
@@ -1133,433 +1142,58 @@ int pcmcia_deregister_client(client_handle_t handle)
 } /* deregister_client */
 } /* deregister_client */
 EXPORT_SYMBOL(pcmcia_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)
 static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev)
 {
 {
 	struct pcmcia_socket *socket = class_get_devdata(class_dev);
 	struct pcmcia_socket *socket = class_get_devdata(class_dev);
-	struct pcmcia_bus_socket *s;
 	int ret;
 	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);
 		printk(KERN_ERR "PCMCIA obtaining reference to socket %p failed\n", socket);
-		kfree (s);
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
-	kref_init(&s->refcount);
-    
 	/*
 	/*
 	 * Ugly. But we want to wait for the socket threads to have started up.
 	 * 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..
 	 * We really should let the drivers themselves drive some of this..
 	 */
 	 */
 	msleep(250);
 	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) {
 	if (ret) {
 		printk(KERN_ERR "PCMCIA registration PCCard core failed for socket %p\n", socket);
 		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 (ret);
 	}
 	}
 
 
 	return 0;
 	return 0;
 }
 }
 
 
-
 static void pcmcia_bus_remove_socket(struct class_device *class_dev)
 static void pcmcia_bus_remove_socket(struct class_device *class_dev)
 {
 {
 	struct pcmcia_socket *socket = class_get_devdata(class_dev);
 	struct pcmcia_socket *socket = class_get_devdata(class_dev);
 
 
-	if (!socket || !socket->pcmcia)
+	if (!socket)
 		return;
 		return;
 
 
+	socket->pcmcia_state.dead = 1;
 	pccard_register_pcmcia(socket, NULL);
 	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;
 	return;
 }
 }
@@ -1575,34 +1209,20 @@ static struct class_interface pcmcia_bus_interface = {
 
 
 struct bus_type pcmcia_bus_type = {
 struct bus_type pcmcia_bus_type = {
 	.name = "pcmcia",
 	.name = "pcmcia",
+	.hotplug = pcmcia_bus_hotplug,
 	.match = pcmcia_bus_match,
 	.match = pcmcia_bus_match,
 	.dev_attrs = pcmcia_dev_attrs,
 	.dev_attrs = pcmcia_dev_attrs,
 };
 };
-EXPORT_SYMBOL(pcmcia_bus_type);
 
 
 
 
 static int __init init_pcmcia_bus(void)
 static int __init init_pcmcia_bus(void)
 {
 {
-	int i;
-
 	spin_lock_init(&pcmcia_dev_list_lock);
 	spin_lock_init(&pcmcia_dev_list_lock);
 
 
 	bus_register(&pcmcia_bus_type);
 	bus_register(&pcmcia_bus_type);
 	class_interface_register(&pcmcia_bus_interface);
 	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;
 	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)
 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);
 	bus_unregister(&pcmcia_bus_type);
 }
 }
 module_exit(exit_pcmcia_bus);
 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");
 MODULE_ALIAS("ds");

+ 21 - 0
drivers/pcmcia/ds_internal.h

@@ -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

+ 16 - 7
drivers/pcmcia/i82365.c

@@ -669,11 +669,13 @@ static int __init is_alive(u_short sock)
     if ((stat & I365_CS_DETECT) && (stat & I365_CS_POWERON) &&
     if ((stat & I365_CS_DETECT) && (stat & I365_CS_POWERON) &&
 	(i365_get(sock, I365_INTCTL) & I365_PC_IOCARD) &&
 	(i365_get(sock, I365_INTCTL) & I365_PC_IOCARD) &&
 	(i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(0)) &&
 	(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];
     struct i82365_socket *t = &socket[sockets-ns];
 
 
     base = 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");
     if (base == 0) printk("\n");
     printk(KERN_INFO "  %s", pcic[type].name);
     printk(KERN_INFO "  %s", pcic[type].name);
@@ -803,7 +811,7 @@ static void __init isa_probe(void)
     }
     }
 #endif
 #endif
 
 
-    if (check_region(i365_base, 2) != 0) {
+    if (!request_region(i365_base, 2, "i82365")) {
 	if (sockets == 0)
 	if (sockets == 0)
 	    printk("port conflict at %#lx\n", i365_base);
 	    printk("port conflict at %#lx\n", i365_base);
 	return;
 	return;
@@ -1441,6 +1449,7 @@ static void __exit exit_i82365(void)
 	i365_set(i, I365_CSCINT, 0);
 	i365_set(i, I365_CSCINT, 0);
 	release_region(socket[i].ioaddr, 2);
 	release_region(socket[i].ioaddr, 2);
     }
     }
+    release_region(i365_base, 2);
 #ifdef CONFIG_PNP
 #ifdef CONFIG_PNP
     if (i82365_pnpdev)
     if (i82365_pnpdev)
     		pnp_disable_dev(i82365_pnpdev);
     		pnp_disable_dev(i82365_pnpdev);

+ 0 - 34
drivers/pcmcia/pcmcia_compat.c

@@ -74,19 +74,6 @@ int pcmcia_validate_cis(client_handle_t handle, cisinfo_t *info)
 }
 }
 EXPORT_SYMBOL(pcmcia_validate_cis);
 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)
 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);
 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);
-

+ 786 - 0
drivers/pcmcia/pcmcia_ioctl.c

@@ -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");
+}

+ 998 - 0
drivers/pcmcia/pcmcia_resource.c

@@ -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);

+ 7 - 4
drivers/pcmcia/rsrc_mgr.c

@@ -72,7 +72,7 @@ int pcmcia_adjust_resource_info(adjust_t *adj)
 			/* you can't use the old interface if the new
 			/* you can't use the old interface if the new
 			 * one was used before */
 			 * one was used before */
 			spin_lock_irqsave(&s->lock, flags);
 			spin_lock_irqsave(&s->lock, flags);
-			if ((s->resource_setup_done) &&
+			if ((s->resource_setup_new) &&
 			    !(s->resource_setup_old)) {
 			    !(s->resource_setup_old)) {
 				spin_unlock_irqrestore(&s->lock, flags);
 				spin_unlock_irqrestore(&s->lock, flags);
 				continue;
 				continue;
@@ -105,29 +105,32 @@ void pcmcia_validate_mem(struct pcmcia_socket *s)
 }
 }
 EXPORT_SYMBOL(pcmcia_validate_mem);
 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)
 		     unsigned long r_end, struct pcmcia_socket *s)
 {
 {
 	if (s->resource_ops->adjust_io_region)
 	if (s->resource_ops->adjust_io_region)
 		return s->resource_ops->adjust_io_region(res, r_start, r_end, s);
 		return s->resource_ops->adjust_io_region(res, r_start, r_end, s);
 	return -ENOMEM;
 	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)
 		   unsigned long align, struct pcmcia_socket *s)
 {
 {
 	if (s->resource_ops->find_io)
 	if (s->resource_ops->find_io)
 		return s->resource_ops->find_io(base, num, align, s);
 		return s->resource_ops->find_io(base, num, align, s);
 	return NULL;
 	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)
 				 int low, struct pcmcia_socket *s)
 {
 {
 	if (s->resource_ops->find_mem)
 	if (s->resource_ops->find_mem)
 		return s->resource_ops->find_mem(base, num, align, low, s);
 		return s->resource_ops->find_mem(base, num, align, low, s);
 	return NULL;
 	return NULL;
 }
 }
+EXPORT_SYMBOL(pcmcia_find_mem_region);
 
 
 void release_resource_db(struct pcmcia_socket *s)
 void release_resource_db(struct pcmcia_socket *s)
 {
 {

+ 114 - 56
drivers/pcmcia/rsrc_nonstatic.c

@@ -372,6 +372,9 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s)
 	   base, base+num-1);
 	   base, base+num-1);
     bad = fail = 0;
     bad = fail = 0;
     step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
     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 */
     /* cis_readable wants to map 2x map_size */
     if (step < 2 * s->map_size)
     if (step < 2 * s->map_size)
 	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) {
 	for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
 		mm = *m;
 		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)
 		   unsigned long align, struct pcmcia_socket *s)
 {
 {
 	struct resource *res = make_resource(0, num, IORESOURCE_IO, s->dev.class_id);
 	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;
 	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 resource *res = make_resource(0, num, IORESOURCE_MEM, s->dev.class_id);
 	struct socket_data *s_data = s->resource_data;
 	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;
 	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);
 	down(&rsrc_sem);
-	switch (adj->Action) {
+	switch (action) {
 	case ADD_MANAGED_RESOURCE:
 	case ADD_MANAGED_RESOURCE:
-		ret = add_interval(&data->mem_db, base, num);
+		ret = add_interval(&data->mem_db, start, size);
 		break;
 		break;
 	case REMOVE_MANAGED_RESOURCE:
 	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;
 			struct pcmcia_socket *socket;
 			down_read(&pcmcia_socket_list_rwsem);
 			down_read(&pcmcia_socket_list_rwsem);
 			list_for_each_entry(socket, &pcmcia_socket_list, socket_list)
 			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;
 		break;
 	default:
 	default:
-		ret = CS_UNSUPPORTED_FUNCTION;
+		ret = -EINVAL;
 	}
 	}
 	up(&rsrc_sem);
 	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;
 	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);
 	down(&rsrc_sem);
-	switch (adj->Action) {
+	switch (action) {
 	case ADD_MANAGED_RESOURCE:
 	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;
 			break;
 		}
 		}
 #ifdef CONFIG_PCMCIA_PROBE
 #ifdef CONFIG_PCMCIA_PROBE
 		if (probe_io)
 		if (probe_io)
-			do_io_probe(s, base, num);
+			do_io_probe(s, start, size);
 #endif
 #endif
 		break;
 		break;
 	case REMOVE_MANAGED_RESOURCE:
 	case REMOVE_MANAGED_RESOURCE:
-		sub_interval(&data->io_db, base, num);
+		sub_interval(&data->io_db, start, size);
 		break;
 		break;
 	default:
 	default:
-		ret = CS_UNSUPPORTED_FUNCTION;
+		ret = -EINVAL;
 		break;
 		break;
 	}
 	}
 	up(&rsrc_sem);
 	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)
 static int nonstatic_adjust_resource_info(struct pcmcia_socket *s, adjust_t *adj)
 {
 {
+	unsigned long end;
+
 	switch (adj->Resource) {
 	switch (adj->Resource) {
 	case RES_MEMORY_RANGE:
 	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:
 	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;
 	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)
 static int nonstatic_init(struct pcmcia_socket *s)
 {
 {
 	struct socket_data *data;
 	struct socket_data *data;
@@ -783,6 +847,8 @@ static int nonstatic_init(struct pcmcia_socket *s)
 
 
 	s->resource_data = (void *) data;
 	s->resource_data = (void *) data;
 
 
+	nonstatic_autoadd_resources(s);
+
 	return 0;
 	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);
 	struct pcmcia_socket *s = class_get_devdata(class_dev);
 	unsigned long start_addr, end_addr;
 	unsigned long start_addr, end_addr;
-	unsigned int add = 1;
-	adjust_t adj;
+	unsigned int add = ADD_MANAGED_RESOURCE;
 	ssize_t ret = 0;
 	ssize_t ret = 0;
 
 
 	ret = sscanf (buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
 	ret = sscanf (buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
 	if (ret != 2) {
 	if (ret != 2) {
 		ret = sscanf (buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
 		ret = sscanf (buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
-		add = 0;
+		add = REMOVE_MANAGED_RESOURCE;
 		if (ret != 2) {
 		if (ret != 2) {
 			ret = sscanf (buf, "0x%lx - 0x%lx", &start_addr, &end_addr);
 			ret = sscanf (buf, "0x%lx - 0x%lx", &start_addr, &end_addr);
-			add = 1;
+			add = ADD_MANAGED_RESOURCE;
 			if (ret != 2)
 			if (ret != 2)
 				return -EINVAL;
 				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)
 	if (end_addr <= start_addr)
 		return -EINVAL;
 		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;
 	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);
 	struct pcmcia_socket *s = class_get_devdata(class_dev);
 	unsigned long start_addr, end_addr;
 	unsigned long start_addr, end_addr;
-	unsigned int add = 1;
-	adjust_t adj;
+	unsigned int add = ADD_MANAGED_RESOURCE;
 	ssize_t ret = 0;
 	ssize_t ret = 0;
 
 
 	ret = sscanf (buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
 	ret = sscanf (buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
 	if (ret != 2) {
 	if (ret != 2) {
 		ret = sscanf (buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
 		ret = sscanf (buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
-		add = 0;
+		add = REMOVE_MANAGED_RESOURCE;
 		if (ret != 2) {
 		if (ret != 2) {
 			ret = sscanf (buf, "0x%lx - 0x%lx", &start_addr, &end_addr);
 			ret = sscanf (buf, "0x%lx - 0x%lx", &start_addr, &end_addr);
-			add = 1;
+			add = ADD_MANAGED_RESOURCE;
 			if (ret != 2)
 			if (ret != 2)
 				return -EINVAL;
 				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)
 	if (end_addr <= start_addr)
 		return -EINVAL;
 		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;
 	return ret ? ret : count;
 }
 }

+ 156 - 10
drivers/pcmcia/socket_sysfs.c

@@ -163,28 +163,164 @@ static ssize_t pccard_store_resource(struct class_device *dev, const char *buf,
 		return -EINVAL;
 		return -EINVAL;
 
 
 	spin_lock_irqsave(&s->lock, flags);
 	spin_lock_irqsave(&s->lock, flags);
-	if (!s->resource_setup_done) {
+	if (!s->resource_setup_done)
 		s->resource_setup_done = 1;
 		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);
 		down(&s->skt_sem);
-		if ((s->callback) &&
-		    (s->state & SOCKET_PRESENT) &&
+		if ((s->callback) && (s->state & SOCKET_PRESENT) &&
 		    !(s->state & SOCKET_CARDBUS)) {
 		    !(s->state & SOCKET_CARDBUS)) {
 			if (try_module_get(s->callback->owner)) {
 			if (try_module_get(s->callback->owner)) {
-				s->callback->resources_done(s);
+				s->callback->requery(s);
 				module_put(s->callback->owner);
 				module_put(s->callback->owner);
 			}
 			}
 		}
 		}
 		up(&s->skt_sem);
 		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[] = {
 static struct class_device_attribute *pccard_socket_attributes[] = {
@@ -199,6 +335,13 @@ static struct class_device_attribute *pccard_socket_attributes[] = {
 	NULL,
 	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)
 static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev)
 {
 {
 	struct class_device_attribute **attr;
 	struct class_device_attribute **attr;
@@ -209,6 +352,8 @@ static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev)
 		if (ret)
 		if (ret)
 			break;
 			break;
 	}
 	}
+	if (!ret)
+		ret = sysfs_create_bin_file(&class_dev->kobj, &pccard_cis_attr);
 
 
 	return ret;
 	return ret;
 }
 }
@@ -217,6 +362,7 @@ static void __devexit pccard_sysfs_remove_socket(struct class_device *class_dev)
 {
 {
 	struct class_device_attribute **attr;
 	struct class_device_attribute **attr;
 
 
+	sysfs_remove_bin_file(&class_dev->kobj, &pccard_cis_attr);
 	for (attr = pccard_socket_attributes; *attr; attr++)
 	for (attr = pccard_socket_attributes; *attr; attr++)
 		class_device_remove_file(class_dev, *attr);
 		class_device_remove_file(class_dev, *attr);
 }
 }

+ 5 - 1
drivers/pcmcia/yenta_socket.c

@@ -549,6 +549,11 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ
 	unsigned offset;
 	unsigned offset;
 	unsigned mask;
 	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 */
 	/* The granularity of the memory limit is 4kB, on IO it's 4 bytes */
 	mask = ~0xfff;
 	mask = ~0xfff;
 	if (type & IORESOURCE_IO)
 	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;
 	offset = 0x1c + 8*nr;
 	bus = socket->dev->subordinate;
 	bus = socket->dev->subordinate;
-	res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr;
 	res->name = bus->name;
 	res->name = bus->name;
 	res->flags = type;
 	res->flags = type;
 	res->start = 0;
 	res->start = 0;

+ 11 - 0
drivers/scsi/pcmcia/aha152x_stub.c

@@ -318,6 +318,16 @@ static int aha152x_event(event_t event, int priority,
     return 0;
     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 = {
 static struct pcmcia_driver aha152x_cs_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -325,6 +335,7 @@ static struct pcmcia_driver aha152x_cs_driver = {
 	},
 	},
 	.attach		= aha152x_attach,
 	.attach		= aha152x_attach,
 	.detach		= aha152x_detach,
 	.detach		= aha152x_detach,
+	.id_table       = aha152x_ids,
 };
 };
 
 
 static int __init init_aha152x_cs(void)
 static int __init init_aha152x_cs(void)

+ 10 - 0
drivers/scsi/pcmcia/fdomain_stub.c

@@ -299,6 +299,15 @@ static int fdomain_event(event_t event, int priority,
     return 0;
     return 0;
 } /* fdomain_event */
 } /* 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 = {
 static struct pcmcia_driver fdomain_cs_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -306,6 +315,7 @@ static struct pcmcia_driver fdomain_cs_driver = {
 	},
 	},
 	.attach		= fdomain_attach,
 	.attach		= fdomain_attach,
 	.detach		= fdomain_detach,
 	.detach		= fdomain_detach,
+	.id_table       = fdomain_ids,
 };
 };
 
 
 static int __init init_fdomain_cs(void)
 static int __init init_fdomain_cs(void)

+ 13 - 0
drivers/scsi/pcmcia/nsp_cs.c

@@ -2125,6 +2125,18 @@ static int nsp_cs_event(event_t		       event,
  *	module entry point
  *	module entry point
  *====================================================================*/
  *====================================================================*/
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68))
 #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 = {
 static struct pcmcia_driver nsp_driver = {
 	.owner          = THIS_MODULE,
 	.owner          = THIS_MODULE,
 	.drv            = {
 	.drv            = {
@@ -2132,6 +2144,7 @@ static struct pcmcia_driver nsp_driver = {
 	},
 	},
 	.attach         = nsp_cs_attach,
 	.attach         = nsp_cs_attach,
 	.detach         = nsp_cs_detach,
 	.detach         = nsp_cs_detach,
+	.id_table	= nsp_cs_ids,
 };
 };
 #endif
 #endif
 
 

+ 22 - 0
drivers/scsi/pcmcia/qlogic_stub.c

@@ -395,6 +395,27 @@ static int qlogic_event(event_t event, int priority, event_callback_args_t * arg
 	return 0;
 	return 0;
 }				/* qlogic_event */
 }				/* 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 = {
 static struct pcmcia_driver qlogic_cs_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
@@ -403,6 +424,7 @@ static struct pcmcia_driver qlogic_cs_driver = {
 	},
 	},
 	.attach		= qlogic_attach,
 	.attach		= qlogic_attach,
 	.detach		= qlogic_detach,
 	.detach		= qlogic_detach,
+	.id_table       = qlogic_ids,
 };
 };
 
 
 static int __init init_qlogic_cs(void)
 static int __init init_qlogic_cs(void)

+ 9 - 0
drivers/scsi/pcmcia/sym53c500_cs.c

@@ -999,6 +999,14 @@ MODULE_AUTHOR("Bob Tracy <rct@frus.com>");
 MODULE_DESCRIPTION("SYM53C500 PCMCIA SCSI driver");
 MODULE_DESCRIPTION("SYM53C500 PCMCIA SCSI driver");
 MODULE_LICENSE("GPL");
 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 = {
 static struct pcmcia_driver sym53c500_cs_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -1006,6 +1014,7 @@ static struct pcmcia_driver sym53c500_cs_driver = {
 	},
 	},
 	.attach		= SYM53C500_attach,
 	.attach		= SYM53C500_attach,
 	.detach		= SYM53C500_detach,
 	.detach		= SYM53C500_detach,
+	.id_table       = sym53c500_ids,
 };
 };
 
 
 static int __init
 static int __init

+ 106 - 0
drivers/serial/serial_cs.c

@@ -772,6 +772,111 @@ serial_event(event_t event, int priority, event_callback_args_t * args)
 	return 0;
 	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 = {
 static struct pcmcia_driver serial_cs_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -779,6 +884,7 @@ static struct pcmcia_driver serial_cs_driver = {
 	},
 	},
 	.attach		= serial_attach,
 	.attach		= serial_attach,
 	.detach		= serial_detach,
 	.detach		= serial_detach,
+	.id_table	= serial_ids,
 };
 };
 
 
 static int __init init_serial_cs(void)
 static int __init init_serial_cs(void)

+ 7 - 0
drivers/telephony/ixj_pcmcia.c

@@ -295,6 +295,12 @@ static int ixj_event(event_t event, int priority, event_callback_args_t * args)
 	return 0;
 	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 = {
 static struct pcmcia_driver ixj_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -302,6 +308,7 @@ static struct pcmcia_driver ixj_driver = {
 	},
 	},
 	.attach		= ixj_attach,
 	.attach		= ixj_attach,
 	.detach		= ixj_detach,
 	.detach		= ixj_detach,
+	.id_table	= ixj_ids,
 };
 };
 
 
 static int __init ixj_pcmcia_init(void)
 static int __init ixj_pcmcia_init(void)

+ 8 - 13
drivers/usb/host/sl811_cs.c

@@ -68,13 +68,6 @@ static const char driver_name[DEV_NAME_LEN]  = "sl811_cs";
 
 
 static dev_link_t *dev_list = NULL;
 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 {
 typedef struct local_info_t {
 	dev_link_t		link;
 	dev_link_t		link;
 	dev_node_t		node;
 	dev_node_t		node;
@@ -373,7 +366,7 @@ static dev_link_t *sl811_cs_attach(void)
 	local_info_t *local;
 	local_info_t *local;
 	dev_link_t *link;
 	dev_link_t *link;
 	client_reg_t client_reg;
 	client_reg_t client_reg;
-	int ret, i;
+	int ret;
 
 
 	local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
 	local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
 	if (!local)
 	if (!local)
@@ -385,11 +378,6 @@ static dev_link_t *sl811_cs_attach(void)
 	/* Initialize */
 	/* Initialize */
 	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
 	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
 	link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
 	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->irq.Handler = NULL;
 
 
 	link->conf.Attributes = 0;
 	link->conf.Attributes = 0;
@@ -418,6 +406,12 @@ static dev_link_t *sl811_cs_attach(void)
 	return link;
 	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 = {
 static struct pcmcia_driver sl811_cs_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.drv		= {
 	.drv		= {
@@ -425,6 +419,7 @@ static struct pcmcia_driver sl811_cs_driver = {
 	},
 	},
 	.attach		= sl811_cs_attach,
 	.attach		= sl811_cs_attach,
 	.detach		= sl811_cs_detach,
 	.detach		= sl811_cs_detach,
+	.id_table	= sl811_ids,
 };
 };
 
 
 /*====================================================================*/
 /*====================================================================*/

+ 8 - 4
include/asm-i386/ide.h

@@ -41,13 +41,17 @@ static __inline__ int ide_default_irq(unsigned long base)
 
 
 static __inline__ unsigned long ide_default_io_base(int index)
 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) {
 	switch (index) {
 		case 0:	return 0x1f0;
 		case 0:	return 0x1f0;
 		case 1:	return 0x170;
 		case 1:	return 0x170;
-		case 2: return 0x1e8;
-		case 3: return 0x168;
-		case 4: return 0x1e0;
-		case 5: return 0x160;
 		default:
 		default:
 			return 0;
 			return 0;
 	}
 	}

+ 2 - 0
include/asm-sparc64/auxio.h

@@ -75,6 +75,8 @@
 
 
 #ifndef __ASSEMBLY__
 #ifndef __ASSEMBLY__
 
 
+extern void __iomem *auxio_register;
+
 #define AUXIO_LTE_ON	1
 #define AUXIO_LTE_ON	1
 #define AUXIO_LTE_OFF	0
 #define AUXIO_LTE_OFF	0
 
 

+ 8 - 8
include/asm-sparc64/floppy.h

@@ -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
  * underruns.  If non-zero, doing_pdma encodes the direction of
  * the transfer for debugging.  1=read 2=write
  * the transfer for debugging.  1=read 2=write
  */
  */
-char *pdma_vaddr;
+unsigned char *pdma_vaddr;
 unsigned long pdma_size;
 unsigned long pdma_size;
 volatile int doing_pdma = 0;
 volatile int doing_pdma = 0;
 
 
@@ -209,8 +209,7 @@ static void sun_fd_enable_dma(void)
 	pdma_areasize = pdma_size;
 	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)
 static int sun_fd_request_irq(void)
 {
 {
@@ -220,8 +219,8 @@ static int sun_fd_request_irq(void)
 	if(!once) {
 	if(!once) {
 		once = 1;
 		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);
 		return ((error == 0) ? 0 : -1);
 	}
 	}
@@ -615,7 +614,7 @@ static unsigned long __init sun_floppy_init(void)
 		struct linux_ebus *ebus;
 		struct linux_ebus *ebus;
 		struct linux_ebus_device *edev = NULL;
 		struct linux_ebus_device *edev = NULL;
 		unsigned long config = 0;
 		unsigned long config = 0;
-		unsigned long auxio_reg;
+		void __iomem *auxio_reg;
 
 
 		for_each_ebus(ebus) {
 		for_each_ebus(ebus) {
 			for_each_ebusdev(edev, 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
 		/* Make sure the high density bit is set, some systems
 		 * (most notably Ultra5/Ultra10) come up with it clear.
 		 * (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);
 		writel(readl(auxio_reg)|0x2, auxio_reg);
 
 
 		sun_pci_ebus_dev = ebus->self;
 		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);
 		spin_lock_init(&sun_pci_fd_ebus_dma.lock);
 
 
 		/* XXX ioremap */
 		/* 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)
 		if (!sun_pci_fd_ebus_dma.regs)
 			return 0;
 			return 0;
 
 

+ 1 - 6
include/asm-sparc64/irq.h

@@ -19,7 +19,7 @@
 /* You should not mess with this directly. That's the job of irq.c.
 /* 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
  * 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
  * This is currently one DCACHE line, two buckets per L2 cache
  * line.  Keep this in mind please.
  * 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 build_irq(int pil, int inofixup, unsigned long iclr, unsigned long imap);
 extern unsigned int sbus_build_irq(void *sbus, unsigned int ino);
 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)
 static __inline__ void set_softint(unsigned long bits)
 {
 {
 	__asm__ __volatile__("wr	%0, 0x0, %%set_softint"
 	__asm__ __volatile__("wr	%0, 0x0, %%set_softint"

+ 2 - 1
include/asm-sparc64/rwsem.h

@@ -55,8 +55,9 @@ static __inline__ int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
 		"add		%%g1, %1, %%g7\n\t"
 		"add		%%g1, %1, %%g7\n\t"
 		"cas		[%2], %%g1, %%g7\n\t"
 		"cas		[%2], %%g1, %%g7\n\t"
 		"cmp		%%g1, %%g7\n\t"
 		"cmp		%%g1, %%g7\n\t"
+		"membar		#StoreLoad | #StoreStore\n\t"
 		"bne,pn		%%icc, 1b\n\t"
 		"bne,pn		%%icc, 1b\n\t"
-		" membar	#StoreLoad | #StoreStore\n\t"
+		" nop\n\t"
 		"mov		%%g7, %0\n\t"
 		"mov		%%g7, %0\n\t"
 		: "=&r" (tmp)
 		: "=&r" (tmp)
 		: "0" (tmp), "r" (sem)
 		: "0" (tmp), "r" (sem)

+ 19 - 10
include/asm-sparc64/spinlock.h

@@ -52,12 +52,14 @@ static inline void _raw_spin_lock(spinlock_t *lock)
 
 
 	__asm__ __volatile__(
 	__asm__ __volatile__(
 "1:	ldstub		[%1], %0\n"
 "1:	ldstub		[%1], %0\n"
+"	membar		#StoreLoad | #StoreStore\n"
 "	brnz,pn		%0, 2f\n"
 "	brnz,pn		%0, 2f\n"
-"	 membar		#StoreLoad | #StoreStore\n"
+"	 nop\n"
 "	.subsection	2\n"
 "	.subsection	2\n"
 "2:	ldub		[%1], %0\n"
 "2:	ldub		[%1], %0\n"
+"	membar		#LoadLoad\n"
 "	brnz,pt		%0, 2b\n"
 "	brnz,pt		%0, 2b\n"
-"	 membar		#LoadLoad\n"
+"	 nop\n"
 "	ba,a,pt		%%xcc, 1b\n"
 "	ba,a,pt		%%xcc, 1b\n"
 "	.previous"
 "	.previous"
 	: "=&r" (tmp)
 	: "=&r" (tmp)
@@ -95,16 +97,18 @@ static inline void _raw_spin_lock_flags(spinlock_t *lock, unsigned long flags)
 
 
 	__asm__ __volatile__(
 	__asm__ __volatile__(
 "1:	ldstub		[%2], %0\n"
 "1:	ldstub		[%2], %0\n"
-"	brnz,pn		%0, 2f\n"
 "	membar		#StoreLoad | #StoreStore\n"
 "	membar		#StoreLoad | #StoreStore\n"
+"	brnz,pn		%0, 2f\n"
+"	 nop\n"
 "	.subsection	2\n"
 "	.subsection	2\n"
 "2:	rdpr		%%pil, %1\n"
 "2:	rdpr		%%pil, %1\n"
 "	wrpr		%3, %%pil\n"
 "	wrpr		%3, %%pil\n"
 "3:	ldub		[%2], %0\n"
 "3:	ldub		[%2], %0\n"
-"	brnz,pt		%0, 3b\n"
 "	membar		#LoadLoad\n"
 "	membar		#LoadLoad\n"
+"	brnz,pt		%0, 3b\n"
+"	 nop\n"
 "	ba,pt		%%xcc, 1b\n"
 "	ba,pt		%%xcc, 1b\n"
-"	wrpr		%1, %%pil\n"
+"	 wrpr		%1, %%pil\n"
 "	.previous"
 "	.previous"
 	: "=&r" (tmp1), "=&r" (tmp2)
 	: "=&r" (tmp1), "=&r" (tmp2)
 	: "r"(lock), "r"(flags)
 	: "r"(lock), "r"(flags)
@@ -162,12 +166,14 @@ static void inline __read_lock(rwlock_t *lock)
 "4:	 add		%0, 1, %1\n"
 "4:	 add		%0, 1, %1\n"
 "	cas		[%2], %0, %1\n"
 "	cas		[%2], %0, %1\n"
 "	cmp		%0, %1\n"
 "	cmp		%0, %1\n"
+"	membar		#StoreLoad | #StoreStore\n"
 "	bne,pn		%%icc, 1b\n"
 "	bne,pn		%%icc, 1b\n"
-"	 membar		#StoreLoad | #StoreStore\n"
+"	 nop\n"
 "	.subsection	2\n"
 "	.subsection	2\n"
 "2:	ldsw		[%2], %0\n"
 "2:	ldsw		[%2], %0\n"
+"	membar		#LoadLoad\n"
 "	brlz,pt		%0, 2b\n"
 "	brlz,pt		%0, 2b\n"
-"	 membar		#LoadLoad\n"
+"	 nop\n"
 "	ba,a,pt		%%xcc, 4b\n"
 "	ba,a,pt		%%xcc, 4b\n"
 "	.previous"
 "	.previous"
 	: "=&r" (tmp1), "=&r" (tmp2)
 	: "=&r" (tmp1), "=&r" (tmp2)
@@ -204,12 +210,14 @@ static void inline __write_lock(rwlock_t *lock)
 "4:	 or		%0, %3, %1\n"
 "4:	 or		%0, %3, %1\n"
 "	cas		[%2], %0, %1\n"
 "	cas		[%2], %0, %1\n"
 "	cmp		%0, %1\n"
 "	cmp		%0, %1\n"
+"	membar		#StoreLoad | #StoreStore\n"
 "	bne,pn		%%icc, 1b\n"
 "	bne,pn		%%icc, 1b\n"
-"	 membar		#StoreLoad | #StoreStore\n"
+"	 nop\n"
 "	.subsection	2\n"
 "	.subsection	2\n"
 "2:	lduw		[%2], %0\n"
 "2:	lduw		[%2], %0\n"
+"	membar		#LoadLoad\n"
 "	brnz,pt		%0, 2b\n"
 "	brnz,pt		%0, 2b\n"
-"	 membar		#LoadLoad\n"
+"	 nop\n"
 "	ba,a,pt		%%xcc, 4b\n"
 "	ba,a,pt		%%xcc, 4b\n"
 "	.previous"
 "	.previous"
 	: "=&r" (tmp1), "=&r" (tmp2)
 	: "=&r" (tmp1), "=&r" (tmp2)
@@ -240,8 +248,9 @@ static int inline __write_trylock(rwlock_t *lock)
 "	 or		%0, %4, %1\n"
 "	 or		%0, %4, %1\n"
 "	cas		[%3], %0, %1\n"
 "	cas		[%3], %0, %1\n"
 "	cmp		%0, %1\n"
 "	cmp		%0, %1\n"
+"	membar		#StoreLoad | #StoreStore\n"
 "	bne,pn		%%icc, 1b\n"
 "	bne,pn		%%icc, 1b\n"
-"	 membar		#StoreLoad | #StoreStore\n"
+"	 nop\n"
 "	mov		1, %2\n"
 "	mov		1, %2\n"
 "2:"
 "2:"
 	: "=&r" (tmp1), "=&r" (tmp2), "=&r" (result)
 	: "=&r" (tmp1), "=&r" (tmp2), "=&r" (result)

+ 0 - 1
include/asm-sparc64/spitfire.h

@@ -111,7 +111,6 @@ static __inline__ void spitfire_put_dcache_tag(unsigned long addr, unsigned long
 			     "membar	#Sync"
 			     "membar	#Sync"
 			     : /* No outputs */
 			     : /* No outputs */
 			     : "r" (tag), "r" (addr), "i" (ASI_DCACHE_TAG));
 			     : "r" (tag), "r" (addr), "i" (ASI_DCACHE_TAG));
-	__asm__ __volatile__ ("membar #Sync" : : : "memory");
 }
 }
 
 
 /* The instruction cache lines are flushed with this, but note that
 /* The instruction cache lines are flushed with this, but note that

+ 46 - 0
include/linux/mod_devicetable.h

@@ -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 */
 #endif /* LINUX_MOD_DEVICETABLE_H */

+ 2 - 0
include/linux/pci_ids.h

@@ -1815,6 +1815,8 @@
 #define PCI_VENDOR_ID_ITE		0x1283
 #define PCI_VENDOR_ID_ITE		0x1283
 #define PCI_DEVICE_ID_ITE_IT8172G	0x8172
 #define PCI_DEVICE_ID_ITE_IT8172G	0x8172
 #define PCI_DEVICE_ID_ITE_IT8172G_AUDIO 0x0801
 #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_8872		0x8872
 #define PCI_DEVICE_ID_ITE_IT8330G_0	0xe886
 #define PCI_DEVICE_ID_ITE_IT8330G_0	0xe886
 
 

+ 2 - 0
include/pcmcia/ciscode.h

@@ -112,6 +112,8 @@
 
 
 #define MANFID_TDK			0x0105
 #define MANFID_TDK			0x0105
 #define PRODID_TDK_CF010		0x0900
 #define PRODID_TDK_CF010		0x0900
+#define PRODID_TDK_NP9610		0x0d0a
+#define PRODID_TDK_MN3200		0x0e0a
 #define PRODID_TDK_GN3410		0x4815
 #define PRODID_TDK_GN3410		0x4815
 
 
 #define MANFID_TOSHIBA			0x0098
 #define MANFID_TOSHIBA			0x0098

+ 0 - 2
include/pcmcia/cs.h

@@ -396,7 +396,6 @@ struct pcmcia_socket;
 int pcmcia_access_configuration_register(client_handle_t handle, conf_reg_t *reg);
 int pcmcia_access_configuration_register(client_handle_t handle, conf_reg_t *reg);
 int pcmcia_deregister_client(client_handle_t handle);
 int pcmcia_deregister_client(client_handle_t handle);
 int pcmcia_get_configuration_info(client_handle_t handle, config_info_t *config);
 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_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_next_window(window_handle_t *win, win_req_t *req);
 int pcmcia_get_status(client_handle_t handle, cs_status_t *status);
 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_resume_card(struct pcmcia_socket *skt);
 int pcmcia_eject_card(struct pcmcia_socket *skt);
 int pcmcia_eject_card(struct pcmcia_socket *skt);
 int pcmcia_insert_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);
 struct pcmcia_socket * pcmcia_get_socket(struct pcmcia_socket *skt);
 void pcmcia_put_socket(struct pcmcia_socket *skt);
 void pcmcia_put_socket(struct pcmcia_socket *skt);

+ 249 - 0
include/pcmcia/device_id.h

@@ -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, }

+ 6 - 3
include/pcmcia/ds.h

@@ -18,6 +18,8 @@
 
 
 #include <pcmcia/bulkmem.h>
 #include <pcmcia/bulkmem.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs_types.h>
+#include <pcmcia/device_id.h>
+#include <linux/mod_devicetable.h>
 
 
 typedef struct tuple_parse_t {
 typedef struct tuple_parse_t {
     tuple_t		tuple;
     tuple_t		tuple;
@@ -129,12 +131,11 @@ typedef struct dev_link_t {
 
 
 struct pcmcia_socket;
 struct pcmcia_socket;
 
 
-extern struct bus_type pcmcia_bus_type;
-
 struct pcmcia_driver {
 struct pcmcia_driver {
 	dev_link_t		*(*attach)(void);
 	dev_link_t		*(*attach)(void);
 	void			(*detach)(dev_link_t *);
 	void			(*detach)(dev_link_t *);
 	struct module		*owner;
 	struct module		*owner;
+	struct pcmcia_device_id	*id_table;
 	struct device_driver	drv;
 	struct device_driver	drv;
 };
 };
 
 
@@ -173,7 +174,9 @@ struct pcmcia_device {
 	u8			has_manf_id:1;
 	u8			has_manf_id:1;
 	u8			has_card_id:1;
 	u8			has_card_id:1;
 	u8			has_func_id:1;
 	u8			has_func_id:1;
-	u8			reserved:5;
+
+	u8			allow_func_id_match:1;
+	u8			reserved:4;
 
 
 	u8			func_id;
 	u8			func_id;
 	u16			manf_id;
 	u16			manf_id;

+ 30 - 4
include/pcmcia/ss.h

@@ -15,10 +15,12 @@
 #ifndef _LINUX_SS_H
 #ifndef _LINUX_SS_H
 #define _LINUX_SS_H
 #define _LINUX_SS_H
 
 
+#include <linux/config.h>
+#include <linux/device.h>
+
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/bulkmem.h>
 #include <pcmcia/bulkmem.h>
-#include <linux/device.h>
 
 
 /* Definitions for card status flags for GetStatus */
 /* Definitions for card status flags for GetStatus */
 #define SS_WRPROT	0x0001
 #define SS_WRPROT	0x0001
@@ -171,7 +173,7 @@ typedef struct window_t {
 
 
 struct config_t;
 struct config_t;
 struct pcmcia_callback;
 struct pcmcia_callback;
-
+struct user_info_t;
 
 
 struct pcmcia_socket {
 struct pcmcia_socket {
 	struct module			*owner;
 	struct module			*owner;
@@ -216,8 +218,9 @@ struct pcmcia_socket {
 
 
 	/* is set to one if resource setup is done using adjust_resource_info() */
 	/* is set to one if resource setup is done using adjust_resource_info() */
 	u8				resource_setup_old:1;
 	u8				resource_setup_old:1;
+	u8				resource_setup_new:1;
 
 
-	u8				reserved:6;
+	u8				reserved:5;
 
 
 	/* socket operations */
 	/* socket operations */
 	struct pccard_operations *	ops;
 	struct pccard_operations *	ops;
@@ -241,9 +244,32 @@ struct pcmcia_socket {
 	unsigned int			thread_events;
 	unsigned int			thread_events;
 
 
 	/* pcmcia (16-bit) */
 	/* pcmcia (16-bit) */
-	struct pcmcia_bus_socket	*pcmcia;
 	struct pcmcia_callback		*callback;
 	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) */
 	/* cardbus (32-bit) */
 #ifdef CONFIG_CARDBUS
 #ifdef CONFIG_CARDBUS
 	struct resource *		cb_cis_res;
 	struct resource *		cb_cis_res;

+ 39 - 0
scripts/mod/file2alias.c

@@ -287,6 +287,42 @@ static int do_pnp_card_entry(const char *filename,
 	return 1;
 	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 _ */
 /* Ignore any prefix, eg. v850 prepends _ */
 static inline int sym_is(const char *symbol, const char *name)
 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"))
 	else if (sym_is(symname, "__mod_pnp_card_device_table"))
 		do_table(symval, sym->st_size, sizeof(struct pnp_card_device_id),
 		do_table(symval, sym->st_size, sizeof(struct pnp_card_device_id),
 			 do_pnp_card_entry, mod);
 			 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 */
 /* Now add out buffered information to the generated C source */

+ 8 - 1
sound/pcmcia/pdaudiocf/pdaudiocf.c

@@ -380,13 +380,20 @@ static int pdacf_event(event_t event, int priority, event_callback_args_t *args)
 /*
 /*
  * Module entry points
  * 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 = {
 static struct pcmcia_driver pdacf_cs_driver = {
 	.owner          = THIS_MODULE,
 	.owner          = THIS_MODULE,
 	.drv            = {
 	.drv            = {
 		.name   = "snd-pdaudiocf",
 		.name   = "snd-pdaudiocf",
 	},
 	},
 	.attach         = snd_pdacf_attach,
 	.attach         = snd_pdacf_attach,
-	.detach         = snd_pdacf_detach
+	.detach         = snd_pdacf_detach,
+	.id_table	= snd_pdacf_ids,
 };
 };
 
 
 static int __init init_pdacf(void)
 static int __init init_pdacf(void)

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно