📄 i82365.c
字号:
static volatile u_int irq_hits;static u_short irq_sock;static void irq_count(int irq, void *dev, struct pt_regs *regs){ i365_get(irq_sock, I365_CSC); irq_hits++; DEBUG(2, "-> hit on irq %d\n", irq);}static u_int __init test_irq(u_short sock, int irq){ DEBUG(2, " testing ISA irq %d\n", irq); if (request_irq(irq, irq_count, 0, "scan", irq_count) != 0) return 1; irq_hits = 0; irq_sock = sock; __set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/100); if (irq_hits) { free_irq(irq, irq_count); DEBUG(2, " spurious hit!\n"); return 1; } /* Generate one interrupt */ i365_set(sock, I365_CSCINT, I365_CSC_DETECT | (irq << 4)); i365_bset(sock, I365_GENCTL, I365_CTL_SW_IRQ); udelay(1000); free_irq(irq, irq_count); /* mask all interrupts */ i365_set(sock, I365_CSCINT, 0); DEBUG(2, " hits = %d\n", irq_hits); return (irq_hits != 1);}#ifdef CONFIG_ISAstatic u_int __init isa_scan(u_short sock, u_int mask0){ u_int mask1 = 0; int i;#ifdef __alpha__#define PIC 0x4d0 /* Don't probe level-triggered interrupts -- reserved for PCI */ mask0 &= ~(inb(PIC) | (inb(PIC+1) << 8));#endif if (do_scan) { set_bridge_state(sock); i365_set(sock, I365_CSCINT, 0); for (i = 0; i < 16; i++) if ((mask0 & (1 << i)) && (test_irq(sock, i) == 0)) mask1 |= (1 << i); for (i = 0; i < 16; i++) if ((mask1 & (1 << i)) && (test_irq(sock, i) != 0)) mask1 ^= (1 << i); } printk(KERN_INFO " ISA irqs ("); if (mask1) { printk("scanned"); } else { /* Fallback: just find interrupts that aren't in use */ for (i = 0; i < 16; i++) if ((mask0 & (1 << i)) && (_check_irq(i, 0) == 0)) mask1 |= (1 << i); printk("default"); /* If scan failed, default to polled status */ if (!cs_irq && (poll_interval == 0)) poll_interval = HZ; } printk(") = "); for (i = 0; i < 16; i++) if (mask1 & (1<<i)) printk("%s%d", ((mask1 & ((1<<i)-1)) ? "," : ""), i); if (mask1 == 0) printk("none!"); return mask1;}#endif /* CONFIG_ISA *//*====================================================================*//* Time conversion functions */static int to_cycles(int ns){ return ns/cycle_time;}static int to_ns(int cycles){ return cycle_time*cycles;}/*====================================================================*/#ifdef CONFIG_ISAstatic int __init identify(u_short port, u_short sock){ u_char val; int type = -1; /* Use the next free entry in the socket table */ socket[sockets].ioaddr = port; socket[sockets].psock = sock; /* Wake up a sleepy Cirrus controller */ if (wakeup) { i365_bclr(sockets, PD67_MISC_CTL_2, PD67_MC2_SUSPEND); /* Pause at least 50 ms */ mdelay(50); } if ((val = i365_get(sockets, 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(sockets, VG468_MISC, VG468_MISC_VADEMREV); val = i365_get(sockets, I365_IDENT); if (val & I365_IDENT_VADEM) { i365_bclr(sockets, VG468_MISC, VG468_MISC_VADEMREV); type = ((val & 7) >= 4) ? IS_VG469 : IS_VG468; } /* Check for Ricoh chips */ val = i365_get(sockets, RF5C_CHIP_ID); if ((val == RF5C_CHIP_RF5C296) || (val == RF5C_CHIP_RF5C396)) type = IS_RF5Cx96; /* Check for Cirrus CL-PD67xx chips */ i365_set(sockets, PD67_CHIP_INFO, 0); val = i365_get(sockets, PD67_CHIP_INFO); if ((val & PD67_INFO_CHIP_ID) == PD67_INFO_CHIP_ID) { val = i365_get(sockets, PD67_CHIP_INFO); if ((val & PD67_INFO_CHIP_ID) == 0) { type = (val & PD67_INFO_SLOTS) ? IS_PD672X : IS_PD6710; i365_set(sockets, PD67_EXT_INDEX, 0xe5); if (i365_get(sockets, PD67_EXT_INDEX) != 0xe5) type = IS_VT83C469; } } return type;} /* 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(u_short sock){ u_char stat; u_short start, stop; stat = i365_get(sock, I365_STATUS); start = i365_get_pair(sock, I365_IO(0)+I365_W_START); stop = i365_get_pair(sock, I365_IO(0)+I365_W_STOP); if ((stat & I365_CS_DETECT) && (stat & I365_CS_POWERON) && (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD) && (i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(0)) && (check_region(start, stop-start+1) != 0) && ((start & 0xfeef) != 0x02e8)) return 1; else return 0;}/*====================================================================*/static void __init add_socket(u_short port, int psock, int type){ socket[sockets].ioaddr = port; socket[sockets].psock = psock; socket[sockets].type = type; socket[sockets].flags = pcic[type].flags; if (is_alive(sockets)) socket[sockets].flags |= IS_ALIVE; sockets++;}static void __init add_pcic(int ns, int type){ u_int mask = 0, i, base; int use_pci = 0, isa_irq = 0; socket_info_t *t = &socket[sockets-ns]; base = sockets-ns; if (t->ioaddr > 0) request_region(t->ioaddr, 2, "i82365"); if (base == 0) printk("\n"); printk(KERN_INFO " %s", pcic[type].name); printk(" ISA-to-PCMCIA at port %#x ofs 0x%02x", t->ioaddr, t->psock*0x40); printk(", %d socket%s\n", ns, ((ns > 1) ? "s" : ""));#ifdef CONFIG_ISA /* Set host options, build basic interrupt mask */ if (irq_list[0] == -1) mask = irq_mask; else for (i = mask = 0; i < 16; i++) mask |= (1<<irq_list[i]);#endif mask &= I365_MASK & set_bridge_opts(base, ns);#ifdef CONFIG_ISA /* Scan for ISA interrupts */ mask = isa_scan(base, mask);#else printk(KERN_INFO " PCI card interrupts,");#endif #ifdef CONFIG_ISA /* Poll if only two interrupts available */ if (!use_pci && !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 && !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 (cs_irq = 15; cs_irq > 0; cs_irq--) if ((cs_mask & (1 << cs_irq)) && (_check_irq(cs_irq, 0) == 0)) break; if (cs_irq) { grab_irq = 1; isa_irq = cs_irq; printk(" status change on irq %d\n", cs_irq); } }#endif if (!use_pci && !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++) { t[i].cap.features |= SS_CAP_PCCARD; t[i].cap.map_size = 0x1000; t[i].cap.irq_mask = mask; t[i].cs_irq = isa_irq; }} /* add_pcic *//*====================================================================*/#ifdef CONFIG_ISAstatic void __init isa_probe(void){ int i, j, sock, k, ns, id; ioaddr_t port; if (check_region(i365_base, 2) != 0) { if (sockets == 0) printk("port conflict at %#x\n", i365_base); return; } id = identify(i365_base, 0); if ((id == IS_I82365DF) && (identify(i365_base, 1) != id)) { for (i = 0; i < 4; i++) { if (i == ignore) continue; port = i365_base + ((i & 1) << 2) + ((i & 2) << 1); sock = (i & 1) << 1; if (identify(port, sock) == IS_I82365DF) { add_socket(port, sock, IS_VLSI); add_pcic(1, IS_VLSI); } } } else { for (i = 0; i < (extra_sockets ? 8 : 4); i += 2) { port = i365_base + 2*(i>>2); sock = (i & 3); id = identify(port, sock); if (id < 0) continue; for (j = ns = 0; j < 2; j++) { /* Does the socket exist? */ if ((ignore == i+j) || (identify(port, sock+j) < 0)) continue; /* Check for bad socket decode */ for (k = 0; k <= sockets; k++) i365_set(k, I365_MEM(0)+I365_W_OFF, k); for (k = 0; k <= sockets; k++) if (i365_get(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/*====================================================================*/static u_int pending_events[8];static spinlock_t pending_event_lock = SPIN_LOCK_UNLOCKED;static void pcic_bh(void *dummy){ u_int events; int i; for (i=0; i < sockets; i++) { spin_lock_irq(&pending_event_lock); events = pending_events[i]; pending_events[i] = 0; spin_unlock_irq(&pending_event_lock); if (socket[i].handler) socket[i].handler(socket[i].info, events); }}static struct tq_struct pcic_task = { routine: pcic_bh};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(4, "i82365: pcic_interrupt(%d)\n", irq); for (j = 0; j < 20; j++) { active = 0; for (i = 0; i < sockets; i++) { if ((socket[i].cs_irq != irq) && (socket[i].cap.pci_irq != irq)) continue; ISA_LOCK(i, flags); csc = i365_get(i, I365_CSC); if ((csc == 0) || (!socket[i].handler) || (i365_get(i, I365_IDENT) & 0x70)) { ISA_UNLOCK(i, flags); continue; } events = (csc & I365_CSC_DETECT) ? SS_DETECT : 0; if (i365_get(i, 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(i, flags); DEBUG(2, "i82365: socket %d event 0x%02x\n", i, events); if (events) { spin_lock(&pending_event_lock); pending_events[i] |= events; spin_unlock(&pending_event_lock); schedule_task(&pcic_task); } active |= events; } if (!active) break; } if (j == 20) printk(KERN_NOTICE "i82365: infinite loop in interrupt handler\n"); DEBUG(4, "i82365: interrupt done\n");} /* pcic_interrupt */static void pcic_interrupt_wrapper(u_long data){ pcic_interrupt(0, NULL, NULL); poll_timer.expires = jiffies + poll_interval; add_timer(&poll_timer);}/*====================================================================*/static int pcic_register_callback(unsigned int sock, void (*handler)(void *, unsigned int), void * info){ socket[sock].handler = handler; socket[sock].info = info; if (handler == NULL) { MOD_DEC_USE_COUNT; } else { MOD_INC_USE_COUNT; } return 0;} /* pcic_register_callback *//*====================================================================*/static int pcic_inquire_socket(unsigned int sock, socket_cap_t *cap){ *cap = socket[sock].cap; return 0;} /* pcic_inquire_socket *//*====================================================================*/static int i365_get_status(u_short sock, u_int *value){ u_int status; status = i365_get(sock, I365_STATUS); *value = ((status & I365_CS_DETECT) == I365_CS_DETECT) ? SS_DETECT : 0; if (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD) *value |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG; else { *value |= (status & I365_CS_BVD1) ? 0 : SS_BATDEAD; *value |= (status & I365_CS_BVD2) ? 0 : SS_BATWARN; } *value |= (status & I365_CS_WRPROT) ? SS_WRPROT : 0; *value |= (status & I365_CS_READY) ? SS_READY : 0; *value |= (status & I365_CS_POWERON) ? SS_POWERON : 0;#ifdef CONFIG_ISA if (socket[sock].type == IS_VG469) { status = i365_get(sock, VG469_VSENSE); if (socket[sock].psock & 1) { *value |= (status & VG469_VSENSE_B_VS1) ? 0 : SS_3VCARD; *value |= (status & VG469_VSENSE_B_VS2) ? 0 : SS_XVCARD; } else { *value |= (status & VG469_VSENSE_A_VS1) ? 0 : SS_3VCARD; *value |= (status & VG469_VSENSE_A_VS2) ? 0 : SS_XVCARD; } }#endif DEBUG(1, "i82365: GetStatus(%d) = %#4.4x\n", sock, *value); return 0;} /* i365_get_status *//*====================================================================*/static int i365_get_socket(u_short sock, socket_state_t *state){ socket_info_t *t = &socket[sock]; u_char reg, vcc, vpp; reg = i365_get(sock, I365_POWER); state->flags = (reg & I365_PWR_AUTO) ? SS_PWR_AUTO : 0; state->flags |= (reg & I365_PWR_OUT) ? SS_OUTPUT_ENA : 0; vcc = reg & I365_VCC_MASK; vpp = reg & I365_VPP1_MASK; state->Vcc = state->Vpp = 0; if (t->flags & IS_CIRRUS) { if (i365_get(sock, PD67_MISC_CTL_1) & PD67_MC1_VCC_3V) { if (reg & I365_VCC_5V) state->Vcc = 33; if (vpp == I365_VPP1_5V) state->Vpp = 33; } else { if (reg & I365_VCC_5V) state->Vcc = 50; if (vpp == I365_VPP1_5V) state->Vpp = 50; } if (vpp == I365_VPP1_12V) state->Vpp = 120; } else if (t->flags & IS_VG_PWR) { if (i365_get(sock, VG469_VSELECT) & VG469_VSEL_VCC) { if (reg & I365_VCC_5V) state->Vcc = 33; if (vpp == I365_VPP1_5V) state->Vpp = 33; } else { if (reg & I365_VCC_5V) state->Vcc = 50; if (vpp == I365_VPP1_5V) state->Vpp = 50; } if (vpp == I365_VPP1_12V) state->Vpp = 120; } else if (t->flags & IS_DF_PWR) { if (vcc == I365_VCC_3V) state->Vcc = 33; if (vcc == I365_VCC_5V) state->Vcc = 50; if (vpp == I365_VPP1_5V) state->Vpp = 50; if (vpp == I365_VPP1_12V) state->Vpp = 120; } else { if (reg & I365_VCC_5V) { state->Vcc = 50; if (vpp == I365_VPP1_5V) state->Vpp = 50; if (vpp == I365_VPP1_12V) state->Vpp = 120; } } /* IO card, RESET flags, IO interrupt */ reg = i365_get(sock, I365_INTCTL); state->flags |= (reg & I365_PC_RESET) ? 0 : SS_RESET; if (reg & I365_PC_IOCARD) state->flags |= SS_IOCARD; state->io_irq = reg & I365_IRQ_MASK; /* speaker control */ if (t->flags & IS_CIRRUS) { if (i365_get(sock, PD67_MISC_CTL_1) & PD67_MC1_SPKR_ENA) state->flags |= SS_SPKR_ENA; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -