summaryrefslogtreecommitdiffstats
path: root/drivers/pcmcia/yenta.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pcmcia/yenta.c')
-rw-r--r--drivers/pcmcia/yenta.c204
1 files changed, 124 insertions, 80 deletions
diff --git a/drivers/pcmcia/yenta.c b/drivers/pcmcia/yenta.c
index e686a6436..b5a2e35de 100644
--- a/drivers/pcmcia/yenta.c
+++ b/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 @@ static void exca_writew(pci_socket_t *socket, unsigned reg, u16 val)
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 @@ static int yenta_set_socket(pci_socket_t *socket, socket_state_t *state)
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;
@@ -385,13 +380,12 @@ static void yenta_proc_setup(pci_socket_t *socket, struct proc_dir_entry *base)
/* Not done yet */
}
-static void yenta_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static unsigned int yenta_events(pci_socket_t *socket)
{
u8 csc;
u32 cb_event;
unsigned int events;
- pci_socket_t *socket = (pci_socket_t *) dev_id;
-
+
/* Clear interrupt status for the event */
cb_event = cb_readl(socket, CB_SOCKET_EVENT);
cb_writel(socket, CB_SOCKET_EVENT, cb_event);
@@ -407,16 +401,50 @@ static void yenta_interrupt(int irq, void *dev_id, struct pt_regs *regs)
events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0;
events |= (csc & I365_CSC_READY) ? SS_READY : 0;
}
+ return events;
+}
- if (events && socket->handler)
- socket->handler(socket->info, events);
+static void yenta_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned int events;
+ pci_socket_t *socket = (pci_socket_t *) dev_id;
- mod_timer(&socket->timer, jiffies + HZ);
+ events = yenta_events(socket);
+ if (events) {
+ socket->events |= events;
+ wake_up_interruptible(&socket->wait);
+ }
}
-static void yenta_timer(unsigned long data)
+/*
+ * Watch a socket every second (and possibly in a
+ * more timely manner if the state change interrupt
+ * works..)
+ */
+static int yenta_socket_thread(void * data)
{
- yenta_interrupt(0, (pci_socket_t *) data, NULL);
+ pci_socket_t * socket = (pci_socket_t *) data;
+ DECLARE_WAITQUEUE(wait, current);
+
+ daemonize();
+ strcpy(current->comm, "CardBus Watcher");
+
+ do {
+ unsigned int events = socket->events | yenta_events(socket);
+
+ if (events) {
+ socket->events = 0;
+ if (socket->handler)
+ socket->handler(socket->info, events);
+ }
+
+ current->state = TASK_INTERRUPTIBLE;
+ add_wait_queue(&socket->wait, &wait);
+ if (!socket->events)
+ schedule_timeout(HZ);
+ remove_wait_queue(&socket->wait, &wait);
+ } while (!signal_pending(current));
+ return 0;
}
static unsigned int yenta_probe_irq(pci_socket_t *socket)
@@ -424,20 +452,10 @@ static unsigned int yenta_probe_irq(pci_socket_t *socket)
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);
@@ -459,7 +477,13 @@ static unsigned int yenta_probe_irq(pci_socket_t *socket)
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)
@@ -483,6 +507,7 @@ static void yenta_clear_maps(pci_socket_t *socket)
/* 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);
@@ -503,6 +528,19 @@ static int yenta_init(pci_socket_t *socket)
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);
@@ -510,29 +548,6 @@ static int yenta_init(pci_socket_t *socket)
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);
@@ -552,7 +567,7 @@ static void yenta_get_socket_capabilities(pci_socket_t *socket)
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)
@@ -585,11 +600,11 @@ static void yenta_allocate_res(pci_socket_t *socket, int nr, unsigned type)
}
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;
}
@@ -611,12 +626,50 @@ static void yenta_allocate_resources(pci_socket_t *socket)
}
/*
+ * 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;
/*
@@ -645,38 +698,31 @@ static int yenta_open(pci_socket_t *socket)
/* Set up the bridge regions.. */
yenta_allocate_resources(socket);
- /*
- * Always poll the socket too, just in case the cardbus interrupt
- * doesn't exist (it happens), or we just lose an interrupt..
- */
- init_timer(&socket->timer);
- socket->timer.expires = jiffies + HZ;
- socket->timer.data = (unsigned long)socket;
- socket->timer.function = yenta_timer;
- add_timer(&socket->timer);
-
if (dev->irq && !request_irq(dev->irq, yenta_interrupt, SA_SHIRQ, dev->name, socket))
socket->cb_irq = dev->irq;
/* And figure out what the dang thing can do for the PCMCIA layer... */
yenta_get_socket_capabilities(socket);
+ /* 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 = {
@@ -684,7 +730,6 @@ struct pci_socket_ops yenta_operations = {
yenta_close,
yenta_init,
yenta_suspend,
- yenta_inquire,
yenta_get_status,
yenta_get_socket,
yenta_set_socket,
@@ -704,7 +749,6 @@ struct pci_socket_ops ricoh_operations = {
yenta_close,
ricoh_init,
yenta_suspend,
- yenta_inquire,
yenta_get_status,
yenta_get_socket,
yenta_set_socket,