📄 yenta.c
字号:
}static unsigned int yenta_events(pci_socket_t *socket){ u8 csc; u32 cb_event; unsigned int events; /* Clear interrupt status for the event */ cb_event = cb_readl(socket, CB_SOCKET_EVENT); cb_writel(socket, CB_SOCKET_EVENT, cb_event); csc = exca_readb(socket, I365_CSC); events = (cb_event & (CB_CD1EVENT | CB_CD2EVENT)) ? SS_DETECT : 0 ; events |= (csc & I365_CSC_DETECT) ? SS_DETECT : 0; if (exca_readb(socket, I365_INTCTL) & I365_PC_IOCARD) { events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0; } else { events |= (csc & I365_CSC_BVD1) ? SS_BATDEAD : 0; events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0; events |= (csc & I365_CSC_READY) ? SS_READY : 0; } return events;}static void yenta_bh(void *data){ pci_socket_t *socket = data; unsigned int events; spin_lock_irq(&socket->event_lock); events = socket->events; socket->events = 0; spin_unlock_irq(&socket->event_lock); if (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; events = yenta_events(socket); if (events) { spin_lock(&socket->event_lock); socket->events |= events; spin_unlock(&socket->event_lock); schedule_task(&socket->tq_task); }}static void yenta_interrupt_wrapper(unsigned long data){ pci_socket_t *socket = (pci_socket_t *) data; yenta_interrupt(0, (void *)socket, NULL); socket->poll_timer.expires = jiffies + HZ; add_timer(&socket->poll_timer);}/* * Only probe "regular" interrupts, don't * touch dangerous spots like the mouse irq, * because there are mice that apparently * get really confused if they get fondled * too intimately. * * Default to 11, 10, 9, 7, 6, 5, 4, 3. */static u32 isa_interrupts = 0x0ef8;static unsigned int yenta_probe_irq(pci_socket_t *socket, u32 isa_irq_mask){ int i; unsigned long val; u16 bridge_ctrl; u32 mask; /* Set up ISA irq routing to probe the ISA irqs.. */ bridge_ctrl = config_readw(socket, CB_BRIDGE_CONTROL); if (!(bridge_ctrl & CB_BRIDGE_INTR)) { bridge_ctrl |= CB_BRIDGE_INTR; config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl); } /* * Probe for usable interrupts using the force * register to generate bogus card status events. */ cb_writel(socket, CB_SOCKET_EVENT, -1); cb_writel(socket, CB_SOCKET_MASK, CB_CSTSMASK); exca_writeb(socket, I365_CSCINT, 0); val = probe_irq_on() & isa_irq_mask; for (i = 1; i < 16; i++) { if (!((val >> i) & 1)) continue; exca_writeb(socket, I365_CSCINT, I365_CSC_STSCHG | (i << 4)); cb_writel(socket, CB_SOCKET_FORCE, CB_FCARDSTS); udelay(100); cb_writel(socket, CB_SOCKET_EVENT, -1); } cb_writel(socket, CB_SOCKET_MASK, 0); exca_writeb(socket, I365_CSCINT, 0); mask = probe_irq_mask(val) & 0xffff; bridge_ctrl &= ~CB_BRIDGE_INTR; config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl); return mask;}/* * Set static data that doesn't need re-initializing.. */static void yenta_get_socket_capabilities(pci_socket_t *socket, u32 isa_irq_mask){ socket->cap.features |= SS_CAP_PAGE_REGS | SS_CAP_PCCARD | SS_CAP_CARDBUS; socket->cap.map_size = 0x1000; socket->cap.pci_irq = socket->cb_irq; socket->cap.irq_mask = yenta_probe_irq(socket, isa_irq_mask); socket->cap.cb_dev = socket->dev; socket->cap.bus = NULL; printk("Yenta IRQ list %04x, PCI irq%d\n", socket->cap.irq_mask, socket->cb_irq);}extern void cardbus_register(pci_socket_t *socket);/* * 'Bottom half' for the yenta_open routine. Allocate the interrupt line * and register the socket with the upper layers. */static void yenta_open_bh(void * data){ pci_socket_t * socket = (pci_socket_t *) data; /* It's OK to overwrite this now */ socket->tq_task.routine = yenta_bh; if (!socket->cb_irq || request_irq(socket->cb_irq, yenta_interrupt, SA_SHIRQ, socket->dev->name, socket)) { /* No IRQ or request_irq failed. Poll */ socket->cb_irq = 0; /* But zero is a valid IRQ number. */ socket->poll_timer.function = yenta_interrupt_wrapper; socket->poll_timer.data = (unsigned long)socket; socket->poll_timer.expires = jiffies + HZ; add_timer(&socket->poll_timer); } /* Figure out what the dang thing can do for the PCMCIA layer... */ yenta_get_socket_capabilities(socket, isa_interrupts); printk("Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE)); /* Register it with the pcmcia layer.. */ cardbus_register(socket); MOD_DEC_USE_COUNT;}static void yenta_clear_maps(pci_socket_t *socket){ int i; pccard_io_map io = { 0, 0, 0, 0, 1 }; pccard_mem_map mem = { 0, 0, 0, 0, 0, 0 }; mem.sys_stop = 0x0fff; yenta_set_socket(socket, &dead_socket); for (i = 0; i < 2; i++) { io.map = i; yenta_set_io_map(socket, &io); } for (i = 0; i < 5; i++) { mem.map = i; yenta_set_mem_map(socket, &mem); }}/* * Initialize the standard cardbus registers */static void yenta_config_init(pci_socket_t *socket){ u16 bridge; struct pci_dev *dev = socket->dev; pci_set_power_state(socket->dev, 0); config_writel(socket, CB_LEGACY_MODE_BASE, 0); config_writel(socket, PCI_BASE_ADDRESS_0, dev->resource[0].start); config_writew(socket, PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_WAIT); /* MAGIC NUMBERS! Fixme */ config_writeb(socket, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES / 4); config_writeb(socket, PCI_LATENCY_TIMER, 168); config_writeb(socket, PCI_SEC_LATENCY_TIMER, 176); config_writeb(socket, PCI_PRIMARY_BUS, dev->bus->number); 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); /* Redo card voltage interrogation */ cb_writel(socket, CB_SOCKET_FORCE, CB_CVSTEST);}/* Called at resume and initialization events */static int yenta_init(pci_socket_t *socket){ yenta_config_init(socket); yenta_clear_maps(socket); return 0;}static int yenta_suspend(pci_socket_t *socket){ yenta_set_socket(socket, &dead_socket); /* * This does not work currently. The controller * loses too much informationduring D3 to come up * cleanly. We should probably fix yenta_init() * to update all the critical registers, notably * the IO and MEM bridging region data.. That is * something that pci_set_power_state() should * probably know about bridges anyway. * pci_set_power_state(socket->dev, 3); */ return 0;}static void yenta_allocate_res(pci_socket_t *socket, int nr, unsigned type){ struct pci_bus *bus; struct resource *root, *res; u32 start, end; u32 align, size, min, max; unsigned offset; offset = 0x1c + 8*nr; bus = socket->dev->subordinate; res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr; res->name = bus->name; res->flags = type; res->start = 0; res->end = 0; root = pci_find_parent_resource(socket->dev, res); if (!root) return; start = config_readl(socket, offset); end = config_readl(socket, offset+4) | 0xfff; if (start && end > start) { res->start = start; res->end = end; request_resource(root, res); return; } align = size = 4*1024*1024; min = PCIBIOS_MIN_MEM; max = ~0U; if (type & IORESOURCE_IO) { align = 1024; size = 256; min = PCIBIOS_MIN_IO; max = 0xffff; } if (allocate_resource(root, res, size, min, max, align, NULL, NULL) < 0) return; config_writel(socket, offset, res->start); config_writel(socket, offset+4, res->end);}/* * Allocate the bridge mappings for the device.. */static void yenta_allocate_resources(pci_socket_t *socket){ yenta_allocate_res(socket, 0, IORESOURCE_MEM|IORESOURCE_PREFETCH); yenta_allocate_res(socket, 1, IORESOURCE_MEM); yenta_allocate_res(socket, 2, IORESOURCE_IO); yenta_allocate_res(socket, 3, IORESOURCE_IO); /* PCI isn't clever enough to use this one yet */}/* * 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); else del_timer_sync(&sock->poll_timer); 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##_##ystatic struct cardbus_override_struct { unsigned short vendor; unsigned short device; struct pci_socket_ops *op;} cardbus_override[] = { { PD(TI,1130), &ti113x_ops }, { PD(TI,1031), &ti_ops }, { PD(TI,1131), &ti113x_ops }, { PD(TI,1250), &ti1250_ops }, { PD(TI,1220), &ti_ops }, { PD(TI,1221), &ti_ops }, { PD(TI,1210), &ti_ops }, { PD(TI,1450), &ti_ops }, { PD(TI,1225), &ti_ops }, { PD(TI,1251A), &ti_ops }, { PD(TI,1211), &ti_ops }, { PD(TI,1251B), &ti_ops }, { PD(TI,1420), &ti_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; /* * Do some basic sanity checking.. */ if (pci_enable_device(dev)) return -1; if (!pci_resource_start(dev, 0)) { printk("No cardbus resource!\n"); return -1; } /* * Ok, start setup.. Map the cardbus registers, * and request the IRQ. */ socket->base = ioremap(pci_resource_start(dev, 0), 0x1000); if (!socket->base) return -1; yenta_config_init(socket); /* Disable all events */ cb_writel(socket, CB_SOCKET_MASK, 0x0); /* Set up the bridge regions.. */ yenta_allocate_resources(socket); socket->cb_irq = dev->irq; /* 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; } } } /* Get the PCMCIA kernel thread to complete the initialisation later. We can't do this here, because, er, because Linus says so :) */ socket->tq_task.routine = yenta_open_bh; socket->tq_task.data = socket; MOD_INC_USE_COUNT; schedule_task(&socket->tq_task); return 0;}/* * Standard plain cardbus - no frills, no extensions */struct pci_socket_ops yenta_operations = { yenta_open, yenta_close, yenta_init, yenta_suspend, yenta_get_status, yenta_get_socket, yenta_set_socket, yenta_get_io_map, yenta_set_io_map, yenta_get_mem_map, yenta_set_mem_map, yenta_proc_setup};EXPORT_SYMBOL(yenta_operations);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -