📄 i82365.c
字号:
/* Pause at least 50 ms */ mdelay(50); } if ((val = i365_get(s, I365_IDENT)) & 0x70) return -1; switch (val) { case 0x82: type = IS_I82365A; break; case 0x83: type = IS_I82365B; break; case 0x84: type = IS_I82365DF; break; case 0x88: case 0x89: case 0x8a: type = IS_IBM; break; } /* Check for Vadem VG-468 chips */ outb(0x0e, port); outb(0x37, port); i365_bset(s, VG468_MISC, VG468_MISC_VADEMREV); val = i365_get(s, I365_IDENT); if (val & I365_IDENT_VADEM) { i365_bclr(s, VG468_MISC, VG468_MISC_VADEMREV); type = ((val & 7) >= 4) ? IS_VG469 : IS_VG468; } /* Check for Ricoh chips */ val = i365_get(s, RF5C_CHIP_ID); if ((val == RF5C_CHIP_RF5C296) || (val == RF5C_CHIP_RF5C396)) type = IS_RF5Cx96; /* Check for Cirrus CL-PD67xx chips */ i365_set(s, PD67_CHIP_INFO, 0); val = i365_get(s, PD67_CHIP_INFO); if ((val & PD67_INFO_CHIP_ID) == PD67_INFO_CHIP_ID) { val = i365_get(s, PD67_CHIP_INFO); if ((val & PD67_INFO_CHIP_ID) == 0) { type = (val & PD67_INFO_SLOTS) ? IS_PD672X : IS_PD6710; i365_set(s, PD67_EXT_INDEX, 0xe5); if (i365_get(s, PD67_EXT_INDEX) != 0xe5) type = IS_VT83C469; } } return type;} /* isa_identify */#endif/*====================================================================== See if a card is present, powered up, in IO mode, and already bound to a (non PC Card) Linux driver. We leave these alone. We make an exception for cards that seem to be serial devices. ======================================================================*/static int __init is_alive(socket_info_t *s){ u_char stat; u_short start, stop; stat = i365_get(s, I365_STATUS); start = i365_get_pair(s, I365_IO(0)+I365_W_START); stop = i365_get_pair(s, I365_IO(0)+I365_W_STOP); if ((stop - start < 0x40) && (stop - start >= 0x07) && ((start & 0xfeef) != 0x02e8) && (start >= 0x100) && (stat & I365_CS_DETECT) && (stat & I365_CS_POWERON) && (i365_get(s, I365_INTCTL) & I365_PC_IOCARD) && (i365_get(s, I365_ADDRWIN) & I365_ENA_IO(0)) && (check_region(start, stop-start+1) != 0)) return 1; else return 0;}/*====================================================================*/static void __init add_socket(u_short port, int psock, int type){ socket_info_t *s = socket+sockets; s->ioaddr = port; s->psock = psock; s->type = type; s->flags = pcic[type].flags; if (is_alive(s)) s->flags |= IS_ALIVE; sockets++;}static void __init add_pcic(int ns, int type){ u_int mask = 0, i; int use_pci = 0, isa_irq = 0; socket_info_t *s = &socket[sockets-ns]; if (s->ioaddr > 0) request_region(s->ioaddr, 2, "i82365"); printk(KERN_INFO " %s", pcic[type].name);#ifdef CONFIG_PCI if (s->flags & IS_UNKNOWN) printk(" [%04x %04x]", s->vendor, s->device); printk(" rev %02x", s->revision); if (s->flags & IS_CARDBUS) printk(" PCI-to-CardBus at slot %02x:%02x, mem %#08x\n", s->bus, PCI_SLOT(s->devfn), s->cb_phys); else if (s->flags & IS_PCI) printk(" PCI-to-PCMCIA at slot %02x:%02x, port %#x\n", s->bus, PCI_SLOT(s->devfn), s->ioaddr); else#endif printk(" ISA-to-PCMCIA at port %#x ofs 0x%02x\n", s->ioaddr, s->psock*0x40);#ifdef CONFIG_ISA if (irq_list[0] == -1) mask = irq_mask; else for (i = mask = 0; i < 16; i++) mask |= (1<<irq_list[i]);#endif /* Set host options, build basic interrupt mask */ mask &= I365_ISA_IRQ_MASK & set_bridge_opts(s, ns);#ifdef CONFIG_PCI /* Can we use PCI interrupts for card status changes? */ if (pci_csc || pci_int) { for (i = 0; i < ns; i++) if (!s[i].cap.pci_irq || !pci_scan(&s[i])) break; use_pci = (i == ns); }#endif#ifdef CONFIG_ISA /* Scan, report ISA card interrupts */ if (mask) mask = isa_scan(s, mask);#endif#ifdef CONFIG_PCI if (!mask) printk(KERN_INFO " %s card interrupts,", (use_pci && pci_int) ? "PCI" : "*NO*"); if (use_pci && pci_csc) printk(" PCI status changes\n");#endif#ifdef CONFIG_ISA /* Poll if only two sensible interrupts available */ if (!(use_pci && pci_csc) && !poll_interval) { u_int tmp = (mask & 0xff20); tmp = tmp & (tmp-1); if ((tmp & (tmp-1)) == 0) poll_interval = HZ; } /* Only try an ISA cs_irq if this is the first controller */ if (!(use_pci && pci_csc) && !grab_irq && (cs_irq || !poll_interval)) { /* Avoid irq 12 unless it is explicitly requested */ u_int cs_mask = mask & ((cs_irq) ? (1<<cs_irq) : ~(1<<12)); for (isa_irq = 15; isa_irq > 0; isa_irq--) if (cs_mask & (1 << isa_irq)) break; if (isa_irq) { grab_irq = 1; cs_irq = isa_irq; printk(" status change on irq %d\n", isa_irq); } }#endif if (!(use_pci && pci_csc) && !isa_irq) { if (poll_interval == 0) poll_interval = HZ; printk(" polling interval = %d ms\n", poll_interval*1000/HZ); } /* Update socket interrupt information, capabilities */ for (i = 0; i < ns; i++) { s[i].cap.features |= SS_CAP_PCCARD; s[i].cap.map_size = 0x1000; s[i].cap.irq_mask = mask; if (!use_pci) s[i].cap.pci_irq = 0; s[i].cs_irq = isa_irq;#ifdef CONFIG_PCI if (s[i].flags & IS_CARDBUS) { s[i].cap.features |= SS_CAP_CARDBUS; cb_set_irq_mode(s+i, pci_csc && s[i].cap.pci_irq, 0); }#endif }} /* add_pcic *//*====================================================================*/#ifdef CONFIG_PCIstatic int __init pci_lookup(u_int class, struct pci_dev **id, u_char *bus, u_char *devfn){ if ((*id = pci_find_class(class<<8, *id)) != NULL) { *bus = (*id)->bus->number; *devfn = (*id)->devfn; return 0; } else return -1;}static void __init add_pci_bridge(int type, u_short v, u_short d){ socket_info_t *s = &socket[sockets]; u_int addr, ns; pci_enable_device(pci_find_slot(s->bus, s->devfn)); if (type == PCIC_COUNT) type = IS_UNK_PCI; pci_readl(s, PCI_BASE_ADDRESS_0, &addr); addr &= ~0x1; for (ns = 0; ns < ((type == IS_I82092AA) ? 4 : 2); ns++) { s[ns].bus = s->bus; s[ns].devfn = s->devfn; s[ns].vendor = v; s[ns].device = d; add_socket(addr, ns, type); } add_pcic(ns, type);}static int check_cb_mapping(socket_info_t *s){ u_int state = cb_readl(s, CB_SOCKET_STATE) >> 16; /* A few sanity checks to validate the bridge mapping */ if ((cb_readb(s, 0x800+I365_IDENT) & 0x70) || (cb_readb(s, 0x800+I365_CSC) && cb_readb(s, 0x800+I365_CSC) && cb_readb(s, 0x800+I365_CSC)) || cb_readl(s, CB_SOCKET_FORCE) || ((state & ~0x3000) || !(state & 0x3000))) return 1; return 0;}static void __init add_cb_bridge(int type, u_short v, u_short d0){ socket_info_t *s = &socket[sockets]; u_char bus = s->bus, devfn = s->devfn; u_short d, ns; u_char a, r, max; /* PCI bus enumeration is broken on some systems */ for (ns = 0; ns < sockets; ns++) if ((socket[ns].bus == bus) && (socket[ns].devfn == devfn)) return; if (type == PCIC_COUNT) type = IS_UNK_CARDBUS; pci_readb(s, PCI_HEADER_TYPE, &a); pci_readb(s, PCI_CLASS_REVISION, &r); max = (a & 0x80) ? 8 : 1; for (ns = 0; ns < max; ns++, s++, devfn++) { s->bus = bus; s->devfn = devfn; if (pci_readw(s, PCI_DEVICE_ID, &d) || (d != d0)) break; s->vendor = v; s->device = d; s->revision = r; pci_enable_device(pci_find_slot(bus, devfn)); pci_set_power_state(pci_find_slot(bus, devfn), 0); /* Set up CardBus register mapping */ pci_writel(s, CB_LEGACY_MODE_BASE, 0); pci_readl(s, PCI_BASE_ADDRESS_0, &s->cb_phys); if (s->cb_phys == 0) { printk("\n" KERN_NOTICE " Bridge register mapping failed:" " check cb_mem_base setting\n"); break; } s->cb_virt = ioremap(s->cb_phys, 0x1000); if (check_cb_mapping(s) != 0) { printk("\n" KERN_NOTICE " Bad bridge mapping at " "0x%08x!\n", s->cb_phys); break; } request_mem_region(s->cb_phys, 0x1000, "i82365"); add_socket(0, 0, type); } if (ns == 0) return; add_pcic(ns, type); /* Look up PCI bus bridge structures if needed */ s -= ns; for (a = 0; a < ns; a++) { struct pci_dev *self = pci_find_slot(bus, s[a].devfn);#if (LINUX_VERSION_CODE >= VERSION(2,3,40)) s[a].cap.cb_bus = self->subordinate;#else struct pci_bus *child; for (child = self->bus->children; child; child = child->next) if (child->number == s[a].cap.cardbus) break; s[a].cap.cb_bus = child;#endif }}static void __init pci_probe(u_int class){ socket_info_t *s = &socket[sockets]; u_short i, v, d; struct pci_dev *id; id = 0; while (pci_lookup(class, &id, &s->bus, &s->devfn) == 0) { if (PCI_FUNC(s->devfn) != 0) continue; pci_readw(s, PCI_VENDOR_ID, &v); pci_readw(s, PCI_DEVICE_ID, &d); for (i = 0; i < PCIC_COUNT; i++) if ((pcic[i].vendor == v) && (pcic[i].device == d)) break; /* The "ToPIC95-A" is unusable as a CardBus bridge */ if (i == IS_TOPIC95_A) continue; if (((i < PCIC_COUNT) && (pcic[i].flags & IS_CARDBUS)) || (class == PCI_CLASS_BRIDGE_CARDBUS)) add_cb_bridge(i, v, d); else add_pci_bridge(i, v, d); s = &socket[sockets]; }}#endif/*====================================================================*/#ifdef CONFIG_ISAstatic void __init isa_probe(ioaddr_t base){ int i, j, sock, k, ns, id; ioaddr_t port; if (check_region(base, 2) != 0) { if (sockets == 0) printk("port conflict at %#x\n", base); return; } id = isa_identify(base, 0); if ((id == IS_I82365DF) && (isa_identify(base, 1) != id)) { for (i = 0; i < 4; i++) { if (i == ignore) continue; port = base + ((i & 1) << 2) + ((i & 2) << 1); sock = (i & 1) << 1; if (isa_identify(port, sock) == IS_I82365DF) { add_socket(port, sock, IS_VLSI); add_pcic(1, IS_VLSI); } } } else { for (i = 0; i < 4; i += 2) { port = base + 2*(i>>2); sock = (i & 3); id = isa_identify(port, sock); if (id < 0) continue; for (j = ns = 0; j < 2; j++) { /* Does the socket exist? */ if ((ignore == i+j) || (isa_identify(port, sock+j) < 0)) continue; /* Check for bad socket decode */ for (k = 0; k <= sockets; k++) i365_set(socket+k, I365_MEM(0)+I365_W_OFF, k); for (k = 0; k <= sockets; k++) if (i365_get(socket+k, I365_MEM(0)+I365_W_OFF) != k) break; if (k <= sockets) break; add_socket(port, sock+j, id); ns++; } if (ns != 0) add_pcic(ns, id); } }}#endif/*====================================================================== The card status event handler. This may either be interrupt driven or polled. It monitors mainly for card insert and eject events; there are various other kinds of events that can be monitored (ready/busy, status change, etc), but they are almost never used. ======================================================================*/static void pcic_interrupt(int irq, void *dev, struct pt_regs *regs){ int i, j, csc; u_int events, active;#ifdef CONFIG_ISA u_long flags = 0;#endif DEBUG(2, "i82365: pcic_interrupt(%d)\n", irq); for (j = 0; j < 20; j++) { active = 0; for (i = 0; i < sockets; i++) { socket_info_t *s = &socket[i]; if ((s->cs_irq != irq) && (s->cap.pci_irq != irq)) continue; ISA_LOCK(s, flags); csc = i365_get(s, I365_CSC);#ifdef CONFIG_PCI if ((s->flags & IS_CARDBUS) && (cb_readl(s, CB_SOCKET_EVENT) & CB_SE_CCD)) { cb_writel(s, CB_SOCKET_EVENT, CB_SE_CCD); csc |= I365_CSC_DETECT; }#endif if ((csc == 0) || (!s->handler) || (i365_get(s, I365_IDENT) & 0x70)) { ISA_UNLOCK(s, flags); continue; } events = (csc & I365_CSC_DETECT) ? SS_DETECT : 0; if (i365_get(s, 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; } ISA_UNLOCK(s, flags); DEBUG(1, "i82365: socket %d event 0x%04x\n", i, events); if (events) s->handler(s->info, events); active |= events; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -