📄 tcic.c
字号:
/* jump start interrupt handler, if needed */ tcic_interrupt(0, NULL, NULL); if (register_ss_entry(sockets, &tcic_service) != 0) { printk(KERN_NOTICE "tcic: register_ss_entry() failed\n"); release_region(tcic_base, 16); if (cs_irq != 0) free_irq(cs_irq, tcic_interrupt); return -ENODEV; } return 0; } /* init_tcic *//*====================================================================*/static void __exit exit_tcic(void){ u_long flags; unregister_ss_entry(&tcic_service); save_flags(flags); cli(); if (cs_irq != 0) { tcic_aux_setw(TCIC_AUX_SYSCFG, TCIC_SYSCFG_AUTOBUSY|0x0a00); free_irq(cs_irq, tcic_interrupt); } del_timer(&poll_timer); restore_flags(flags); release_region(tcic_base, 16);} /* exit_tcic *//*====================================================================*/static void tcic_interrupt(int irq, void *dev, struct pt_regs *regs){ int i, quick = 0; u_char latch, sstat; u_short psock; u_int events; static volatile int active = 0; if (active) { printk(KERN_NOTICE "tcic: reentered interrupt handler!\n"); return; } else active = 1; DEBUG(2, "tcic: tcic_interrupt()\n"); for (i = 0; i < sockets; i++) { psock = socket_table[i].psock; tcic_setl(TCIC_ADDR, (psock << TCIC_ADDR_SS_SHFT) | TCIC_ADDR_INDREG | TCIC_SCF1(psock)); sstat = tcic_getb(TCIC_SSTAT); latch = sstat ^ socket_table[psock].last_sstat; socket_table[i].last_sstat = sstat; if (tcic_getb(TCIC_ICSR) & TCIC_ICSR_CDCHG) { tcic_setb(TCIC_ICSR, TCIC_ICSR_CLEAR); quick = 1; } if ((latch == 0) || (socket_table[psock].handler == NULL)) continue; events = (latch & TCIC_SSTAT_CD) ? SS_DETECT : 0; events |= (latch & TCIC_SSTAT_WP) ? SS_WRPROT : 0; if (tcic_getw(TCIC_DATA) & TCIC_SCF1_IOSTS) { events |= (latch & TCIC_SSTAT_LBAT1) ? SS_STSCHG : 0; } else { events |= (latch & TCIC_SSTAT_RDY) ? SS_READY : 0; events |= (latch & TCIC_SSTAT_LBAT1) ? SS_BATDEAD : 0; events |= (latch & TCIC_SSTAT_LBAT2) ? SS_BATWARN : 0; } DEBUG(1, "tcic: socket %d event 0x%04x\n", i, events); if (events) socket_table[i].handler(socket_table[i].info, events); } /* Schedule next poll, if needed */ if (((cs_irq == 0) || quick) && !timer_pending(&poll_timer)) { poll_timer.expires = jiffies + (quick ? poll_quick : poll_interval); add_timer(&poll_timer); } active = 0; DEBUG(2, "tcic: interrupt done\n"); } /* tcic_interrupt */static void tcic_timer(u_long data){ DEBUG(2, "tcic: tcic_timer()\n"); tcic_interrupt(0, NULL, NULL);}/*====================================================================*/static int tcic_register_callback(u_short lsock, ss_callback_t *call){ if (call == NULL) { socket_table[lsock].handler = NULL; MOD_DEC_USE_COUNT; } else { MOD_INC_USE_COUNT; socket_table[lsock].handler = call->handler; socket_table[lsock].info = call->info; } return 0;} /* tcic_register_callback *//*====================================================================*/static int tcic_get_status(u_short lsock, u_int *value){ u_short psock = socket_table[lsock].psock; u_char reg; tcic_setl(TCIC_ADDR, (psock << TCIC_ADDR_SS_SHFT) | TCIC_ADDR_INDREG | TCIC_SCF1(psock)); reg = tcic_getb(TCIC_SSTAT); *value = (reg & TCIC_SSTAT_CD) ? SS_DETECT : 0; *value |= (reg & TCIC_SSTAT_WP) ? SS_WRPROT : 0; if (tcic_getw(TCIC_DATA) & TCIC_SCF1_IOSTS) { *value |= (reg & TCIC_SSTAT_LBAT1) ? SS_STSCHG : 0; } else { *value |= (reg & TCIC_SSTAT_RDY) ? SS_READY : 0; *value |= (reg & TCIC_SSTAT_LBAT1) ? SS_BATDEAD : 0; *value |= (reg & TCIC_SSTAT_LBAT2) ? SS_BATWARN : 0; } reg = tcic_getb(TCIC_PWR); if (reg & (TCIC_PWR_VCC(psock)|TCIC_PWR_VPP(psock))) *value |= SS_POWERON; DEBUG(1, "tcic: GetStatus(%d) = %#2.2x\n", lsock, *value); return 0;} /* tcic_get_status */ /*====================================================================*/static int tcic_inquire_socket(u_short lsock, socket_cap_t *cap){ *cap = tcic_cap; return 0;} /* tcic_inquire_socket *//*====================================================================*/static int tcic_get_socket(u_short lsock, socket_state_t *state){ u_short psock = socket_table[lsock].psock; u_char reg; u_short scf1, scf2; tcic_setl(TCIC_ADDR, (psock << TCIC_ADDR_SS_SHFT) | TCIC_ADDR_INDREG | TCIC_SCF1(psock)); scf1 = tcic_getw(TCIC_DATA); state->flags = (scf1 & TCIC_SCF1_IOSTS) ? SS_IOCARD : 0; state->flags |= (scf1 & TCIC_SCF1_DMA_MASK) ? SS_DMA_MODE : 0; state->flags |= (scf1 & TCIC_SCF1_SPKR) ? SS_SPKR_ENA : 0; if (tcic_getb(TCIC_SCTRL) & TCIC_SCTRL_ENA) state->flags |= SS_OUTPUT_ENA; state->io_irq = scf1 & TCIC_SCF1_IRQ_MASK; if (state->io_irq == 1) state->io_irq = 11; reg = tcic_getb(TCIC_PWR); state->Vcc = state->Vpp = 0; if (reg & TCIC_PWR_VCC(psock)) { if (reg & TCIC_PWR_VPP(psock)) state->Vcc = 50; else state->Vcc = state->Vpp = 50; } else { if (reg & TCIC_PWR_VPP(psock)) { state->Vcc = 50; state->Vpp = 120; } } reg = tcic_aux_getb(TCIC_AUX_ILOCK); state->flags |= (reg & TCIC_ILOCK_CRESET) ? SS_RESET : 0; /* Card status change interrupt mask */ tcic_setw(TCIC_ADDR, TCIC_SCF2(psock)); scf2 = tcic_getw(TCIC_DATA); state->csc_mask = (scf2 & TCIC_SCF2_MCD) ? 0 : SS_DETECT; if (state->flags & SS_IOCARD) { state->csc_mask |= (scf2 & TCIC_SCF2_MLBAT1) ? 0 : SS_STSCHG; } else { state->csc_mask |= (scf2 & TCIC_SCF2_MLBAT1) ? 0 : SS_BATDEAD; state->csc_mask |= (scf2 & TCIC_SCF2_MLBAT2) ? 0 : SS_BATWARN; state->csc_mask |= (scf2 & TCIC_SCF2_MRDY) ? 0 : SS_READY; } DEBUG(1, "tcic: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, " "io_irq %d, csc_mask %#2.2x\n", lsock, state->flags, state->Vcc, state->Vpp, state->io_irq, state->csc_mask); return 0;} /* tcic_get_socket *//*====================================================================*/static int tcic_set_socket(u_short lsock, socket_state_t *state){ u_short psock = socket_table[lsock].psock; u_char reg; u_short scf1, scf2; DEBUG(1, "tcic: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " "io_irq %d, csc_mask %#2.2x)\n", lsock, state->flags, state->Vcc, state->Vpp, state->io_irq, state->csc_mask); tcic_setw(TCIC_ADDR+2, (psock << TCIC_SS_SHFT) | TCIC_ADR2_INDREG); reg = tcic_getb(TCIC_PWR); reg &= ~(TCIC_PWR_VCC(psock) | TCIC_PWR_VPP(psock)); if (state->Vcc == 50) { switch (state->Vpp) { case 0: reg |= TCIC_PWR_VCC(psock) | TCIC_PWR_VPP(psock); break; case 50: reg |= TCIC_PWR_VCC(psock); break; case 120: reg |= TCIC_PWR_VPP(psock); break; default: return -EINVAL; } } else if (state->Vcc != 0) return -EINVAL; if (reg != tcic_getb(TCIC_PWR)) tcic_setb(TCIC_PWR, reg); reg = TCIC_ILOCK_HOLD_CCLK | TCIC_ILOCK_CWAIT; if (state->flags & SS_OUTPUT_ENA) { tcic_setb(TCIC_SCTRL, TCIC_SCTRL_ENA); reg |= TCIC_ILOCK_CRESENA; } else tcic_setb(TCIC_SCTRL, 0); if (state->flags & SS_RESET) reg |= TCIC_ILOCK_CRESET; tcic_aux_setb(TCIC_AUX_ILOCK, reg); tcic_setw(TCIC_ADDR, TCIC_SCF1(psock)); scf1 = TCIC_SCF1_FINPACK; scf1 |= TCIC_IRQ(state->io_irq); if (state->flags & SS_IOCARD) { scf1 |= TCIC_SCF1_IOSTS; if (state->flags & SS_SPKR_ENA) scf1 |= TCIC_SCF1_SPKR; if (state->flags & SS_DMA_MODE) scf1 |= TCIC_SCF1_DREQ2 << TCIC_SCF1_DMA_SHIFT; } tcic_setw(TCIC_DATA, scf1); /* Some general setup stuff, and configure status interrupt */ reg = TCIC_WAIT_ASYNC | TCIC_WAIT_SENSE | to_cycles(250); tcic_aux_setb(TCIC_AUX_WCTL, reg); tcic_aux_setw(TCIC_AUX_SYSCFG, TCIC_SYSCFG_AUTOBUSY|0x0a00| TCIC_IRQ(cs_irq)); /* Card status change interrupt mask */ tcic_setw(TCIC_ADDR, TCIC_SCF2(psock)); scf2 = TCIC_SCF2_MALL; if (state->csc_mask & SS_DETECT) scf2 &= ~TCIC_SCF2_MCD; if (state->flags & SS_IOCARD) { if (state->csc_mask & SS_STSCHG) reg &= ~TCIC_SCF2_MLBAT1; } else { if (state->csc_mask & SS_BATDEAD) reg &= ~TCIC_SCF2_MLBAT1; if (state->csc_mask & SS_BATWARN) reg &= ~TCIC_SCF2_MLBAT2; if (state->csc_mask & SS_READY) reg &= ~TCIC_SCF2_MRDY; } tcic_setw(TCIC_DATA, scf2); /* For the ISA bus, the irq should be active-high totem-pole */ tcic_setb(TCIC_IENA, TCIC_IENA_CDCHG | TCIC_IENA_CFG_HIGH); return 0;} /* tcic_set_socket */ /*====================================================================*/static int tcic_get_io_map(u_short lsock, struct pccard_io_map *io){ u_short psock = socket_table[lsock].psock; u_short base, ioctl; u_int addr; if (io->map > 1) return -EINVAL; tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT)); addr = TCIC_IWIN(psock, io->map); tcic_setw(TCIC_ADDR, addr + TCIC_IBASE_X); base = tcic_getw(TCIC_DATA); tcic_setw(TCIC_ADDR, addr + TCIC_ICTL_X); ioctl = tcic_getw(TCIC_DATA); if (ioctl & TCIC_ICTL_TINY) io->start = io->stop = base; else { io->start = base & (base-1); io->stop = io->start + (base ^ (base-1)); } io->speed = to_ns(ioctl & TCIC_ICTL_WSCNT_MASK); io->flags = (ioctl & TCIC_ICTL_ENA) ? MAP_ACTIVE : 0; switch (ioctl & TCIC_ICTL_BW_MASK) { case TCIC_ICTL_BW_DYN: io->flags |= MAP_AUTOSZ; break; case TCIC_ICTL_BW_16: io->flags |= MAP_16BIT; break; default: break; } DEBUG(3, "tcic: GetIOMap(%d, %d) = %#2.2x, %d ns, " "%#4.4x-%#4.4x\n", lsock, io->map, io->flags, io->speed, io->start, io->stop); return 0;} /* tcic_get_io_map *//*====================================================================*/static int tcic_set_io_map(u_short lsock, struct pccard_io_map *io){ u_short psock = socket_table[lsock].psock; u_int addr; u_short base, len, ioctl; DEBUG(3, "tcic: SetIOMap(%d, %d, %#2.2x, %d ns, " "%#4.4x-%#4.4x)\n", lsock, io->map, io->flags, io->speed, io->start, io->stop); if ((io->map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) || (io->stop < io->start)) return -EINVAL; tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT)); addr = TCIC_IWIN(psock, io->map); base = io->start; len = io->stop - io->start; /* Check to see that len+1 is power of two, etc */ if ((len & (len+1)) || (base & len)) return -EINVAL; base |= (len+1)>>1; tcic_setw(TCIC_ADDR, addr + TCIC_IBASE_X); tcic_setw(TCIC_DATA, base); ioctl = (psock << TCIC_ICTL_SS_SHFT); ioctl |= (len == 0) ? TCIC_ICTL_TINY : 0; ioctl |= (io->flags & MAP_ACTIVE) ? TCIC_ICTL_ENA : 0; ioctl |= to_cycles(io->speed) & TCIC_ICTL_WSCNT_MASK; if (!(io->flags & MAP_AUTOSZ)) { ioctl |= TCIC_ICTL_QUIET; ioctl |= (io->flags & MAP_16BIT) ? TCIC_ICTL_BW_16 : TCIC_ICTL_BW_8; } tcic_setw(TCIC_ADDR, addr + TCIC_ICTL_X); tcic_setw(TCIC_DATA, ioctl); return 0;} /* tcic_set_io_map *//*====================================================================*/static int tcic_get_mem_map(u_short lsock, struct pccard_mem_map *mem){ u_short psock = socket_table[lsock].psock; u_short addr, ctl; u_long base, mmap; if (mem->map > 3) return -EINVAL; tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT)); addr = TCIC_MWIN(psock, mem->map); tcic_setw(TCIC_ADDR, addr + TCIC_MBASE_X); base = tcic_getw(TCIC_DATA); if (base & TCIC_MBASE_4K_BIT) { mem->sys_start = base & TCIC_MBASE_HA_MASK; mem->sys_stop = mem->sys_start; } else { base &= TCIC_MBASE_HA_MASK; mem->sys_start = (base & (base-1)); mem->sys_stop = mem->sys_start + (base ^ (base-1)); } mem->sys_start = mem->sys_start << TCIC_MBASE_HA_SHFT; mem->sys_stop = (mem->sys_stop << TCIC_MBASE_HA_SHFT) + 0x0fff; tcic_setw(TCIC_ADDR, addr + TCIC_MMAP_X); mmap = tcic_getw(TCIC_DATA); mem->flags = (mmap & TCIC_MMAP_REG) ? MAP_ATTRIB : 0; mmap &= TCIC_MMAP_CA_MASK; mem->card_start = mem->sys_start + (mmap << TCIC_MMAP_CA_SHFT); mem->card_start &= 0x3ffffff; tcic_setw(TCIC_ADDR, addr + TCIC_MCTL_X); ctl = tcic_getw(TCIC_DATA); mem->flags |= (ctl & TCIC_MCTL_ENA) ? MAP_ACTIVE : 0; mem->flags |= (ctl & TCIC_MCTL_B8) ? 0 : MAP_16BIT; mem->flags |= (ctl & TCIC_MCTL_WP) ? MAP_WRPROT : 0; mem->speed = to_ns(ctl & TCIC_MCTL_WSCNT_MASK); DEBUG(3, "tcic: GetMemMap(%d, %d) = %#2.2x, %d ns, " "%#5.5lx-%#5.5lx, %#5.5x\n", lsock, mem->map, mem->flags, mem->speed, mem->sys_start, mem->sys_stop, mem->card_start); return 0;} /* tcic_get_mem_map *//*====================================================================*/ static int tcic_set_mem_map(u_short lsock, struct pccard_mem_map *mem){ u_short psock = socket_table[lsock].psock; u_short addr, ctl; u_long base, len, mmap; DEBUG(3, "tcic: SetMemMap(%d, %d, %#2.2x, %d ns, " "%#5.5lx-%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags, mem->speed, mem->sys_start, mem->sys_stop, mem->card_start); if ((mem->map > 3) || (mem->card_start > 0x3ffffff) || (mem->sys_start > 0xffffff) || (mem->sys_stop > 0xffffff) || (mem->sys_start > mem->sys_stop) || (mem->speed > 1000)) return -EINVAL; tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT)); addr = TCIC_MWIN(psock, mem->map); base = mem->sys_start; len = mem->sys_stop - mem->sys_start; if ((len & (len+1)) || (base & len)) return -EINVAL; if (len == 0x0fff) base = (base >> TCIC_MBASE_HA_SHFT) | TCIC_MBASE_4K_BIT; else base = (base | (len+1)>>1) >> TCIC_MBASE_HA_SHFT; tcic_setw(TCIC_ADDR, addr + TCIC_MBASE_X); tcic_setw(TCIC_DATA, base); mmap = mem->card_start - mem->sys_start; mmap = (mmap >> TCIC_MMAP_CA_SHFT) & TCIC_MMAP_CA_MASK; if (mem->flags & MAP_ATTRIB) mmap |= TCIC_MMAP_REG; tcic_setw(TCIC_ADDR, addr + TCIC_MMAP_X); tcic_setw(TCIC_DATA, mmap); ctl = TCIC_MCTL_QUIET | (psock << TCIC_MCTL_SS_SHFT); ctl |= to_cycles(mem->speed) & TCIC_MCTL_WSCNT_MASK; ctl |= (mem->flags & MAP_16BIT) ? 0 : TCIC_MCTL_B8; ctl |= (mem->flags & MAP_WRPROT) ? TCIC_MCTL_WP : 0; ctl |= (mem->flags & MAP_ACTIVE) ? TCIC_MCTL_ENA : 0; tcic_setw(TCIC_ADDR, addr + TCIC_MCTL_X); tcic_setw(TCIC_DATA, ctl); return 0;} /* tcic_set_mem_map *//*====================================================================*/typedef int (*subfn_t)(u_short, void *); static subfn_t service_table[] = { (subfn_t)&tcic_register_callback, (subfn_t)&tcic_inquire_socket, (subfn_t)&tcic_get_status, (subfn_t)&tcic_get_socket, (subfn_t)&tcic_set_socket, (subfn_t)&tcic_get_io_map, (subfn_t)&tcic_set_io_map, (subfn_t)&tcic_get_mem_map, (subfn_t)&tcic_set_mem_map,};#define NFUNC (sizeof(service_table)/sizeof(subfn_t))static int tcic_service(u_int lsock, u_int cmd, void *arg){ return (cmd < NFUNC) ? service_table[cmd](lsock, arg) : -EINVAL; }/*====================================================================*/module_init(init_tcic);module_exit(exit_tcic);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -