diff options
Diffstat (limited to 'drivers/pcmcia/yenta.c')
-rw-r--r-- | drivers/pcmcia/yenta.c | 204 |
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, |