patch-2.4.22 linux-2.4.22/drivers/pcmcia/i82092.c

Next file: linux-2.4.22/drivers/pcmcia/rsrc_mgr.c
Previous file: linux-2.4.22/drivers/pcmcia/au1000_xxs1500.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.21/drivers/pcmcia/i82092.c linux-2.4.22/drivers/pcmcia/i82092.c
@@ -14,6 +14,8 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/tqueue.h>
 
 #include <pcmcia/cs_types.h>
 #include <pcmcia/ss.h>
@@ -24,6 +26,7 @@
 
 #include "i82092aa.h"
 #include "i82365.h"
+#include "cirrus.h"
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Red Hat, Inc. - Arjan Van De Ven <arjanv@redhat.com>");
@@ -41,8 +44,15 @@
 	      subdevice:PCI_ANY_ID,
 	      class: 0, class_mask:0,
 
-	 },
-	 {} 
+	},
+	{
+	      vendor:PCI_VENDOR_ID_CIRRUS,
+	      device:PCI_DEVICE_ID_CIRRUS_6729,
+	      subvendor:PCI_ANY_ID,
+	      subdevice:PCI_ANY_ID,
+	      class: 0, class_mask:0,
+	},
+	{} 
 };
 
 static struct pci_driver i82092aa_pci_drv = {
@@ -88,14 +98,18 @@
 	void	*info;		/* to be passed to the handler */
 	
 	struct pci_dev *dev;	/* The PCI device for the socket */
+	
+	int type;		/* Type of socket */
+#define IS_I82092	0x0001
+#define IS_PD6729	0x0002
 };
 
 #define MAX_SOCKETS 4
 static struct socket_info sockets[MAX_SOCKETS];
 static int socket_count;  /* shortcut */
 
-int membase = -1;
-int isa_setup;
+static int membase = -1;
+static int isa_setup;
 
 MODULE_PARM(membase, "i");
 MODULE_PARM(isa_setup, "i");
@@ -105,6 +119,7 @@
 	unsigned char configbyte;
 	struct pci_dev *parent;
 	int i;
+	int type;
 	
 	enter("i82092aa_pci_probe");
 	
@@ -114,7 +129,18 @@
 	/* Since we have no memory BARs some firmware we may not
 	   have had PCI_COMMAND_MEM enabled, yet the device needs
 	   it. */
-	pci_read_config_byte(dev, PCI_COMMAND, &configbyte);
+
+	// pci_read_config_byte(dev, PCI_COMMAND, &configbyte);
+	if (dev->vendor == PCI_VENDOR_ID_CIRRUS) {
+		type = IS_PD6729;
+		configbyte = 0;	/* always 2 sockets */
+		printk(KERN_INFO "Cirrus PD6729 PCI to PCMCIA Bridge \n");
+	} else {
+		type = IS_I82092;
+		pci_read_config_byte(dev, 0x40, &configbyte);  /* PCI Configuration Control */
+		printk(KERN_INFO "Intel I82092AA PCI to PCMCIA Bridge \n");
+	}
+
 	if (!(configbyte | PCI_COMMAND_MEMORY)) {
 		dprintk(KERN_DEBUG "Enabling PCI_COMMAND_MEMORY\n");
 		configbyte |= PCI_COMMAND_MEMORY;
@@ -201,6 +227,7 @@
 		sockets[i].cap.map_size = 0x1000;
 		sockets[i].cap.irq_mask = 0;
 		sockets[i].cap.pci_irq  = dev->irq;
+		sockets[i].type = type;
 
 		/* Trick the resource code into doing the right thing... */
 		sockets[i].cap.cb_dev = dev;
@@ -213,10 +240,11 @@
 		}
 	}
 		
-	/* Now, specifiy that all interrupts are to be done as PCI interrupts */
-	configbyte = 0xFF; /* bitmask, one bit per event, 1 = PCI interrupt, 0 = ISA interrupt */
-	pci_write_config_byte(dev, 0x50, configbyte); /* PCI Interrupt Routing Register */
-
+	if (type == IS_I82092) {
+		/* Now, specifiy that all interrupts are to be done as PCI interrupts */
+		configbyte = 0xFF; /* bitmask, one bit per event, 1 = PCI interrupt, 0 = ISA interrupt */
+		pci_write_config_byte(dev, 0x50, configbyte); /* PCI Interrupt Routing Register */
+	}
 
 	/* Register the interrupt handler */
 	dprintk(KERN_DEBUG "Requesting interrupt %i \n",dev->irq);
@@ -238,6 +266,7 @@
 	enter("i82092aa_pci_remove");
 	
 	free_irq(dev->irq, i82092aa_interrupt);
+	flush_scheduled_tasks();
 
 	leave("i82092aa_pci_remove");
 }
@@ -652,6 +681,7 @@
 static int i82092aa_set_socket(unsigned int sock, socket_state_t *state) 
 {
 	unsigned char reg;
+	unsigned long flags;
 	
 	enter("i82092aa_set_socket");
 	
@@ -738,9 +768,26 @@
 	
 	/* now write the value and clear the (probably bogus) pending stuff by doing a dummy read*/
 	
+	spin_lock_irqsave(&port_lock,flags);
+
 	indirect_write(sock,I365_CSCINT,reg);
 	(void)indirect_read(sock,I365_CSC);
 
+	if (sockets[sock].type == IS_PD6729) {
+		/* Configure PD6729 bridge for PCI interrupts */
+		reg |= 0x30;	/* management IRQ: PCI INTA = "irq 3" */
+		indirect_write(sock,I365_CSCINT,reg);
+		(void)indirect_read(sock,I365_CSC);
+
+		reg = indirect_read(sock,I365_INTCTL);
+		reg |= 0x03; /* card IRQ: PCI INTA = "irq 3" */
+		indirect_write(sock,I365_INTCTL,reg);
+
+		indirect_write(sock, PD67_EXT_INDEX, PD67_EXT_CTL_1);
+		indirect_write(sock, PD67_EXT_DATA, PD67_EC1_INV_MGMT_IRQ | PD67_EC1_INV_CARD_IRQ);
+	}
+	spin_unlock_irqrestore(&port_lock,flags);
+
 	leave("i82092aa_set_socket");
 	return 0;
 }
@@ -766,9 +813,10 @@
 	io->speed = to_ns(ioctl & I365_IOCTL_WAIT(map)) ? 1 : 0; /* check this out later */
 	io->flags = 0;
 	
-	if (addr & I365_IOCTL_16BIT(map))
-		io->flags |= MAP_AUTOSZ;
-		
+	io->flags |= (ioctl & I365_IOCTL_0WS(map)) ? MAP_0WS : 0;
+	io->flags |= (ioctl & I365_IOCTL_16BIT(map)) ? MAP_16BIT : 0;
+	io->flags |= (ioctl & I365_IOCTL_IOCS16(map)) ? MAP_AUTOSZ : 0;
+
 	leave("i82092aa_get_io_map");
 	return 0;
 }
@@ -786,7 +834,7 @@
 		leave("i82092aa_set_io_map with invalid map");
 		return -EINVAL;
 	}
-	if ((io->start > 0xffff) || (io->stop > 0xffff) || (io->stop < io->start)){
+	if (io->start > 0xffff || io->stop > 0xffff || io->stop < io->start){
 		leave("i82092aa_set_io_map with invalid io");
 		return -EINVAL;
 	}
@@ -803,9 +851,10 @@
 	            	
 	ioctl = indirect_read(sock,I365_IOCTL) & ~I365_IOCTL_MASK(map);
 	
-	if (io->flags & (MAP_16BIT|MAP_AUTOSZ))
-		ioctl |= I365_IOCTL_16BIT(map);
-		
+    	if (io->flags & MAP_0WS) ioctl |= I365_IOCTL_0WS(map);
+    	if (io->flags & MAP_16BIT) ioctl |= I365_IOCTL_16BIT(map);
+    	if (io->flags & MAP_AUTOSZ) ioctl |= I365_IOCTL_IOCS16(map);
+
 	indirect_write(sock,I365_IOCTL,ioctl);
 	
 	/* Turn the window back on if needed */
@@ -864,11 +913,19 @@
 		mem->flags |= MAP_WRPROT;
 	if (i & I365_MEM_REG)
 		mem->flags |= MAP_ATTRIB;
-	mem->card_start = ( (unsigned long)(i & 0x3fff)<12) + mem->sys_start;
-	mem->card_start &=  0x3ffffff;
 	
+	if (sockets[sock].type == IS_PD6729) {
+		/* Take care of high byte */
+		indirect_write(sock,PD67_EXT_INDEX, PD67_MEM_PAGE(map));
+		addr = indirect_read16(sock, PD67_EXT_DATA) << 24;
+		mem->sys_stop += addr; mem->sys_start += addr;
+		mem->card_start = (unsigned long)(i) + mem->sys_start;
+	} else {
+		mem->card_start = ((unsigned long)(i & 0x3fff)<12) + mem->sys_start;
+		mem->card_start &=  0x3ffffff;
+	}
+
 	dprintk("Card %i is from %lx to %lx \n",sock,mem->sys_start,mem->sys_stop);
-	
 	leave("i82092aa_get_mem_map");
 	return 0;
 	
@@ -895,7 +952,9 @@
 	if (!(mem->flags & MAP_ACTIVE))
 		return 0;
 
-	if ( (mem->card_start > 0x3ffffff) || (mem->sys_start > mem->sys_stop) ||
+	if (sockets[sock].type == IS_PD6729)  {
+		;	/* PD6729 accepts high byte */	
+	} else if ( (mem->card_start > 0x3ffffff) || (mem->sys_start > mem->sys_stop) ||
 	     ((mem->sys_start >> 24) != membase) || ((mem->sys_stop >> 24) != membase) ||
 	     (mem->speed > 1000) ) {
 		leave("i82092aa_set_mem_map: invalid address / speed");
@@ -904,7 +963,6 @@
 	}
 	
 	                 
-	                 
 /* 	printk("set_mem_map: Setting map %i range to %x - %x on socket %i, speed is %i, active = %i \n",map, mem->sys_start,mem->sys_stop,sock,mem->speed,mem->flags & MAP_ACTIVE);  */
 
 	/* write the start address */
@@ -935,6 +993,12 @@
 	
 	indirect_write16(sock,base+I365_W_STOP,i);
 	
+	if (sockets[sock].type == IS_PD6729)  {
+		/* Take care of high byte */
+		indirect_write(sock, PD67_EXT_INDEX, PD67_MEM_PAGE(map));
+		indirect_write16(sock, PD67_EXT_DATA, mem->sys_start >> 24);
+	}
+
 	/* card start */
 	
 	i = (((mem->card_start - mem->sys_start) >> 12) - (membase << 12)) & 0x3fff;
@@ -947,7 +1011,9 @@
 /*		printk("requesting normal memory for socket %i\n",sock);*/
 	}
 	indirect_write16(sock,base+I365_W_OFF,i);
-	indirect_write(sock, I365_CPAGE, membase);
+	if (sockets[sock].type == IS_I82092) {
+		indirect_write(sock, I365_CPAGE, membase);
+	}
 
 	/* Enable the window if necessary */
 	indirect_setbit(sock, I365_ADDRWIN, I365_ENA_MEM(map));

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)