patch-2.3.40 linux/drivers/pcmcia/yenta.c

Next file: linux/drivers/pnp/Makefile
Previous file: linux/drivers/pcmcia/ti113x.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.39/linux/drivers/pcmcia/yenta.c linux/drivers/pcmcia/yenta.c
@@ -15,7 +15,6 @@
 
 #include "yenta.h"
 #include "i82365.h"
-#include "ricoh.h"
 
 /* Don't ask.. */
 #define to_cycles(ns)	((ns)/120)
@@ -68,12 +67,6 @@
 	exca_writeb(socket, reg+1, val >> 8);
 }
 
-static int yenta_inquire(pci_socket_t *socket, socket_cap_t *cap)
-{
-	*cap = socket->cap;
-	return 0;
-}
-
 /*
  * Ugh, mixed-mode cardbus and 16-bit pccard state: things depend
  * on what kind of card is inserted..
@@ -190,20 +183,22 @@
 	u16 bridge;
 
 	yenta_set_power(socket, state);
-	bridge = config_readw(socket, CB_BRIDGE_CONTROL) & ~CB_BRIDGE_CRST;
+	socket->io_irq = state->io_irq;
+	bridge = config_readw(socket, CB_BRIDGE_CONTROL) & ~(CB_BRIDGE_CRST | CB_BRIDGE_INTR);
 	if (cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) {
 		bridge |= (state->flags & SS_RESET) ? CB_BRIDGE_CRST : 0;
-		bridge |= CB_BRIDGE_PREFETCH0 | CB_BRIDGE_POSTEN;
 
 		/* ISA interrupt control? */
-		if (bridge & CB_BRIDGE_INTR) {
+		if (!socket->cb_irq) {
 			u8 intr = exca_readb(socket, I365_INTCTL);
 			intr = (intr & ~0xf) | state->io_irq;
 			exca_writeb(socket, I365_INTCTL, intr);
+			bridge |= CB_BRIDGE_INTR;
 		}
 	} else {
 		u8 reg;
 
+		bridge |= CB_BRIDGE_INTR;
 		reg = exca_readb(socket, I365_INTCTL) & (I365_RING_ENA | I365_INTR_ENA);
 		reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET;
 		reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0;
@@ -426,7 +421,7 @@
  * more timely manner if the state change interrupt
  * works..)
  */
-static int socket_thread(void * data)
+static int yenta_socket_thread(void * data)
 {
 	pci_socket_t * socket = (pci_socket_t *) data;
 	DECLARE_WAITQUEUE(wait, current);
@@ -457,20 +452,10 @@
 	int i;
 	unsigned long val;
 	u16 bridge_ctrl;
+	u32 mask;
 
-	/* Are we set up to route the IO irq to the PCI irq? */
+	/* Set up ISA irq routing to probe the ISA irqs.. */
 	bridge_ctrl = config_readw(socket, CB_BRIDGE_CONTROL);
-	if (socket->cb_irq) {
-		if (bridge_ctrl & CB_BRIDGE_INTR) {
-			bridge_ctrl &= ~CB_BRIDGE_INTR;
-			config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl);
-		}
-		printk("CardBus: using PCI interrupt %d\n", socket->cb_irq);
-		return 1 << socket->cb_irq;
-	}
-
-	/* Uhhuh. No PCI interrupt: try falling back on ISA interrupts */
-	printk("CardBus: Hmm.. No PCI irq routing (irq%d).\n", socket->cb_irq);
 	if (!(bridge_ctrl & CB_BRIDGE_INTR)) {
 		bridge_ctrl |= CB_BRIDGE_INTR;
 		config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl);
@@ -492,7 +477,13 @@
 		cb_writel(socket, CB_SOCKET_EVENT, -1);
 	}
 	cb_writel(socket, CB_SOCKET_MASK, 0);
-	return probe_irq_mask(val) & 0xffff;
+	
+	mask = probe_irq_mask(val) & 0xffff;
+
+	bridge_ctrl &= ~CB_BRIDGE_INTR;
+	config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl);
+
+	return mask;
 }
 
 static void yenta_clear_maps(pci_socket_t *socket)
@@ -516,6 +507,7 @@
 /* Called at resume and initialization events */
 static int yenta_init(pci_socket_t *socket)
 {
+	u16 bridge;
 	struct pci_dev *dev = socket->dev;
 
 	pci_set_power_state(socket->dev, 0);
@@ -536,6 +528,19 @@
 	config_writeb(socket, PCI_SECONDARY_BUS, dev->subordinate->number);
 	config_writeb(socket, PCI_SUBORDINATE_BUS, dev->subordinate->number);
 
+	/*
+	 * Set up the bridging state:
+	 *  - enable write posting.
+	 *  - memory window 0 prefetchable, window 1 non-prefetchable
+	 *  - PCI interrupts enabled if a PCI interrupt exists..
+	 */
+	bridge = config_readw(socket, CB_BRIDGE_CONTROL);
+	bridge &= ~(CB_BRIDGE_CRST | CB_BRIDGE_PREFETCH1 | CB_BRIDGE_INTR | CB_BRIDGE_ISAEN | CB_BRIDGE_VGAEN);
+	bridge |= CB_BRIDGE_PREFETCH0 | CB_BRIDGE_POSTEN;
+	if (!socket->cb_irq)
+		bridge |= CB_BRIDGE_INTR;
+	config_writew(socket, CB_BRIDGE_CONTROL, bridge);
+
 	exca_writeb(socket, I365_GBLCTL, 0x00);
 	exca_writeb(socket, I365_GENCTL, 0x00);
 
@@ -543,29 +548,6 @@
 	return 0;
 }
 
-/*
- * More of an example than anything else... The standard
- * yenta init code works well enough - but this is how
- * you'd do it if you wanted to have a special init sequence.
- */
-static int ricoh_init(pci_socket_t *socket)
-{
-	u16 misc = config_readw(socket, RL5C4XX_MISC);
-	u16 ctl = config_readw(socket, RL5C4XX_16BIT_CTL);
-	u16 io = config_readw(socket, RL5C4XX_16BIT_IO_0);
-	u16 mem = config_readw(socket, RL5C4XX_16BIT_MEM_0);
-
-	ctl = RL5C4XX_16CTL_IO_TIMING | RL5C4XX_16CTL_MEM_TIMING;
-
-	config_writew(socket, RL5C4XX_MISC, misc);
-	config_writew(socket, RL5C4XX_16BIT_CTL, ctl);
-	config_writew(socket, RL5C4XX_16BIT_IO_0, io);
-	config_writew(socket, RL5C4XX_16BIT_MEM_0, mem);
-
-	return yenta_init(socket);
-}
-
-
 static int yenta_suspend(pci_socket_t *socket)
 {
 	yenta_set_socket(socket, &dead_socket);
@@ -585,7 +567,7 @@
 	socket->cap.cb_dev = socket->dev;
 	socket->cap.bus = NULL;
 
-	printk("Yenta IRQ list %04x\n", socket->cap.irq_mask);
+	printk("Yenta IRQ list %04x, PCI irq%d\n", socket->cap.irq_mask, socket->cb_irq);
 }
 
 static void yenta_allocate_res(pci_socket_t *socket, int nr, unsigned type)
@@ -618,11 +600,11 @@
 	}
 
 	align = size = 4*1024*1024;
-	min = 0x10000000; max = ~0U;
+	min = PCIBIOS_MIN_MEM; max = ~0U;
 	if (type & IORESOURCE_IO) {
 		align = 1024;
 		size = 256;
-		min = 0x1000;
+		min = PCIBIOS_MIN_IO;
 		max = 0xffff;
 	}
 		
@@ -644,12 +626,50 @@
 }
 
 /*
+ * Close it down - release our resources and go home..
+ */
+static void yenta_close(pci_socket_t *sock)
+{
+	if (sock->cb_irq)
+		free_irq(sock->cb_irq, sock);
+	if (sock->base)
+		iounmap(sock->base);
+}
+
+#include "ti113x.h"
+#include "ricoh.h"
+
+/*
+ * Different cardbus controllers have slightly different
+ * initialization sequences etc details. List them here..
+ */
+#define PD(x,y) PCI_VENDOR_ID_##x, PCI_DEVICE_ID_##x##_##y
+static struct cardbus_override_struct {
+	unsigned short vendor;
+	unsigned short device;
+	struct pci_socket_ops *op;
+} cardbus_override[] = {
+	{ PD(TI,1130),	&ti113x_ops },
+	{ PD(TI,1131),	&ti113x_ops },
+	{ PD(TI,1250),	&ti1250_ops },
+
+	{ PD(RICOH,RL5C465), &ricoh_ops },
+	{ PD(RICOH,RL5C466), &ricoh_ops },
+	{ PD(RICOH,RL5C475), &ricoh_ops },
+	{ PD(RICOH,RL5C476), &ricoh_ops },
+	{ PD(RICOH,RL5C478), &ricoh_ops }
+};
+
+#define NR_OVERRIDES (sizeof(cardbus_override)/sizeof(struct cardbus_override_struct))
+
+/*
  * Initialize a cardbus controller. Make sure we have a usable
  * interrupt, and that we can map the cardbus area. Fill in the
  * socket information structure..
  */
 static int yenta_open(pci_socket_t *socket)
 {
+	int i;
 	struct pci_dev *dev = socket->dev;
 
 	/*
@@ -684,23 +704,25 @@
 	/* And figure out what the dang thing can do for the PCMCIA layer... */
 	yenta_get_socket_capabilities(socket);
 
-	kernel_thread(socket_thread, socket, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+	/* Do we have special options for the device? */
+	for (i = 0; i < NR_OVERRIDES; i++) {
+		struct cardbus_override_struct *d = cardbus_override+i;
+		if (dev->vendor == d->vendor && dev->device == d->device) {
+			socket->op = d->op;
+			if (d->op->open) {
+				int retval = d->op->open(socket);
+				if (retval < 0)
+					return retval;
+			}
+		}
+	}
+
+	kernel_thread(yenta_socket_thread, socket, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
 	printk("Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE));
 	return 0;
 }
 
 /*
- * Close it down - release our resources and go home..
- */
-static void yenta_close(pci_socket_t *sock)
-{
-	if (sock->cb_irq)
-		free_irq(sock->cb_irq, sock);
-	if (sock->base)
-		iounmap(sock->base);
-}
-
-/*
  * Standard plain cardbus - no frills, no extensions
  */
 struct pci_socket_ops yenta_operations = {
@@ -708,7 +730,6 @@
 	yenta_close,
 	yenta_init,
 	yenta_suspend,
-	yenta_inquire,
 	yenta_get_status,
 	yenta_get_socket,
 	yenta_set_socket,
@@ -728,7 +749,6 @@
 	yenta_close,
 	ricoh_init,
 	yenta_suspend,
-	yenta_inquire,
 	yenta_get_status,
 	yenta_get_socket,
 	yenta_set_socket,

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