tcic.c
来自「linux 内核源代码」· C语言 代码 · 共 827 行 · 第 1/2 页
C
827 行
printk("not found.\n"); release_region(tcic_base, 16); driver_unregister(&tcic_driver); return -ENODEV; } sockets = 0; for (i = 0; i < sock; i++) { if ((i == ignore) || is_active(i)) continue; socket_table[sockets].psock = i; socket_table[sockets].id = get_tcic_id(); socket_table[sockets].socket.owner = THIS_MODULE; /* only 16-bit cards, memory windows must be size-aligned */ /* No PCI or CardBus support */ socket_table[sockets].socket.features = SS_CAP_PCCARD | SS_CAP_MEM_ALIGN; /* irq 14, 11, 10, 7, 6, 5, 4, 3 */ socket_table[sockets].socket.irq_mask = 0x4cf8; /* 4K minimum window size */ socket_table[sockets].socket.map_size = 0x1000; sockets++; } switch (socket_table[0].id) { case TCIC_ID_DB86082: printk("DB86082"); break; case TCIC_ID_DB86082A: printk("DB86082A"); break; case TCIC_ID_DB86084: printk("DB86084"); break; case TCIC_ID_DB86084A: printk("DB86084A"); break; case TCIC_ID_DB86072: printk("DB86072"); break; case TCIC_ID_DB86184: printk("DB86184"); break; case TCIC_ID_DB86082B: printk("DB86082B"); break; default: printk("Unknown ID 0x%02x", socket_table[0].id); } /* Set up polling */ poll_timer.function = &tcic_timer; poll_timer.data = 0; init_timer(&poll_timer); /* Build interrupt mask */ printk(", %d sockets\n" KERN_INFO " irq list (", sockets); if (irq_list_count == 0) mask = irq_mask; else for (i = mask = 0; i < irq_list_count; i++) mask |= (1<<irq_list[i]); /* irq 14, 11, 10, 7, 6, 5, 4, 3 */ mask &= 0x4cf8; /* Scan interrupts */ mask = irq_scan(mask); for (i=0;i<sockets;i++) socket_table[i].socket.irq_mask = mask; /* Check for only two interrupts available */ scan = (mask & (mask-1)); if (((scan & (scan-1)) == 0) && (poll_interval == 0)) poll_interval = HZ; if (poll_interval == 0) { /* Avoid irq 12 unless it is explicitly requested */ u_int cs_mask = mask & ((cs_irq) ? (1<<cs_irq) : ~(1<<12)); for (i = 15; i > 0; i--) if ((cs_mask & (1 << i)) && (request_irq(i, tcic_interrupt, 0, "tcic", tcic_interrupt) == 0)) break; cs_irq = i; if (cs_irq == 0) poll_interval = HZ; } if (socket_table[0].socket.irq_mask & (1 << 11)) printk("sktirq is irq 11, "); if (cs_irq != 0) printk("status change on irq %d\n", cs_irq); else printk("polled status, interval = %d ms\n", poll_interval * 1000 / HZ); for (i = 0; i < sockets; i++) { tcic_setw(TCIC_ADDR+2, socket_table[i].psock << TCIC_SS_SHFT); socket_table[i].last_sstat = tcic_getb(TCIC_SSTAT); } /* jump start interrupt handler, if needed */ tcic_interrupt(0, NULL); platform_device_register(&tcic_device); for (i = 0; i < sockets; i++) { socket_table[i].socket.ops = &tcic_operations; socket_table[i].socket.resource_ops = &pccard_nonstatic_ops; socket_table[i].socket.dev.parent = &tcic_device.dev; ret = pcmcia_register_socket(&socket_table[i].socket); if (ret && i) pcmcia_unregister_socket(&socket_table[0].socket); } return ret; return 0; } /* init_tcic *//*====================================================================*/static void __exit exit_tcic(void){ int i; del_timer_sync(&poll_timer); if (cs_irq != 0) { tcic_aux_setw(TCIC_AUX_SYSCFG, TCIC_SYSCFG_AUTOBUSY|0x0a00); free_irq(cs_irq, tcic_interrupt); } release_region(tcic_base, 16); for (i = 0; i < sockets; i++) { pcmcia_unregister_socket(&socket_table[i].socket); } platform_device_unregister(&tcic_device); driver_unregister(&tcic_driver);} /* exit_tcic *//*====================================================================*/static irqreturn_t tcic_interrupt(int irq, void *dev){ 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 IRQ_NONE; } else active = 1; debug(2, "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) 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; } if (events) { pcmcia_parse_events(&socket_table[i].socket, events); } } /* Schedule next poll, if needed */ if (((cs_irq == 0) || quick) && (!tcic_timer_pending)) { poll_timer.expires = jiffies + (quick ? poll_quick : poll_interval); add_timer(&poll_timer); tcic_timer_pending = 1; } active = 0; debug(2, "interrupt done\n"); return IRQ_HANDLED;} /* tcic_interrupt */static void tcic_timer(u_long data){ debug(2, "tcic_timer()\n"); tcic_timer_pending = 0; tcic_interrupt(0, NULL);} /* tcic_timer *//*====================================================================*/static int tcic_get_status(struct pcmcia_socket *sock, u_int *value){ u_short psock = container_of(sock, struct tcic_socket, socket)->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, "GetStatus(%d) = %#2.2x\n", psock, *value); return 0;} /* tcic_get_status *//*====================================================================*/static int tcic_set_socket(struct pcmcia_socket *sock, socket_state_t *state){ u_short psock = container_of(sock, struct tcic_socket, socket)->psock; u_char reg; u_short scf1, scf2; debug(1, "SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " "io_irq %d, csc_mask %#2.2x)\n", psock, 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_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io){ u_short psock = container_of(sock, struct tcic_socket, socket)->psock; u_int addr; u_short base, len, ioctl; debug(1, "SetIOMap(%d, %d, %#2.2x, %d ns, " "%#lx-%#lx)\n", psock, 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_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *mem){ u_short psock = container_of(sock, struct tcic_socket, socket)->psock; u_short addr, ctl; u_long base, len, mmap; debug(1, "SetMemMap(%d, %d, %#2.2x, %d ns, " "%#llx-%#llx, %#x)\n", psock, mem->map, mem->flags, mem->speed, (unsigned long long)mem->res->start, (unsigned long long)mem->res->end, mem->card_start); if ((mem->map > 3) || (mem->card_start > 0x3ffffff) || (mem->res->start > 0xffffff) || (mem->res->end > 0xffffff) || (mem->res->start > mem->res->end) || (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->res->start; len = mem->res->end - mem->res->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->res->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 *//*====================================================================*/static int tcic_init(struct pcmcia_socket *s){ int i; struct resource res = { .start = 0, .end = 0x1000 }; pccard_io_map io = { 0, 0, 0, 0, 1 }; pccard_mem_map mem = { .res = &res, }; for (i = 0; i < 2; i++) { io.map = i; tcic_set_io_map(s, &io); } for (i = 0; i < 5; i++) { mem.map = i; tcic_set_mem_map(s, &mem); } return 0;}static struct pccard_operations tcic_operations = { .init = tcic_init, .get_status = tcic_get_status, .set_socket = tcic_set_socket, .set_io_map = tcic_set_io_map, .set_mem_map = tcic_set_mem_map,};/*====================================================================*/module_init(init_tcic);module_exit(exit_tcic);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?