📄 sdladrv.c
字号:
break; default: return -EINVAL; } return 0;}/*============================================================================ * Map shared memory window into SDLA address space. */EXPORT_SYMBOL(sdla_mapmem);int sdla_mapmem (sdlahw_t* hw, unsigned long addr){ unsigned port = hw->port; register int tmp; switch (hw->type) { case SDLA_S502A: case SDLA_S502E: if (addr < S502_MAXMEM) { /* verify parameter */ tmp = addr >> 13; /* convert to register mask */ _OUTB(port + 2, tmp); hw->regs[2] = tmp; } else return -EINVAL; break; case SDLA_S503: if (addr < S503_MAXMEM) { /* verify parameter */ tmp = (hw->regs[0] & 0x8F) | ((addr >> 9) & 0x70); _OUTB(port, tmp); hw->regs[0] = tmp; } else return -EINVAL; break; case SDLA_S507: if (addr < S507_MAXMEM) { if (!(_INB(port) & 0x02)) return -EIO; tmp = addr >> 13; /* convert to register mask */ _OUTB(port + 2, tmp); hw->regs[2] = tmp; } else return -EINVAL; break; case SDLA_S508: if (addr < S508_MAXMEM) { tmp = addr >> 13; /* convert to register mask */ _OUTB(port + 2, tmp); hw->regs[2] = tmp; } else return -EINVAL; break; case SDLA_S514: return 0; default: return -EINVAL; } hw->vector = addr & 0xFFFFE000L; return 0;}/*============================================================================ * Enable interrupt generation. */EXPORT_SYMBOL(sdla_inten);int sdla_inten (sdlahw_t* hw){ unsigned port = hw->port; int tmp, i; switch (hw->type) { case SDLA_S502E: /* Note thar interrupt control operations on S502E are allowed * only if CPU is enabled (bit 0 of status register is set). */ if (_INB(port) & 0x01) { _OUTB(port, 0x02); /* bit1 = 1, bit2 = 0 */ _OUTB(port, 0x06); /* bit1 = 1, bit2 = 1 */ hw->regs[0] = 0x06; } else return -EIO; break; case SDLA_S503: tmp = hw->regs[0] | 0x04; _OUTB(port, tmp); hw->regs[0] = tmp; /* update mirror */ for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if (!(_INB(port) & 0x02)) /* verify */ return -EIO; break; case SDLA_S508: tmp = hw->regs[0] | 0x10; _OUTB(port, tmp); hw->regs[0] = tmp; /* update mirror */ for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if (!(_INB(port + 1) & 0x10)) /* verify */ return -EIO; break; case SDLA_S502A: case SDLA_S507: break; case SDLA_S514: break; default: return -EINVAL; } return 0;}/*============================================================================ * Disable interrupt generation. */EXPORT_SYMBOL(sdla_intde);int sdla_intde (sdlahw_t* hw){ unsigned port = hw->port; int tmp, i; switch (hw->type) { case SDLA_S502E: /* Notes: * 1) interrupt control operations are allowed only if CPU is * enabled (bit 0 of status register is set). * 2) disabling interrupts using bit 1 of control register * causes IRQ line go high, therefore we are going to use * 0x04 instead: lower it to inhibit interrupts to PC. */ if (_INB(port) & 0x01) { _OUTB(port, hw->regs[0] & ~0x04); hw->regs[0] &= ~0x04; } else return -EIO; break; case SDLA_S503: tmp = hw->regs[0] & ~0x04; _OUTB(port, tmp); hw->regs[0] = tmp; /* update mirror */ for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if (_INB(port) & 0x02) /* verify */ return -EIO; break; case SDLA_S508: tmp = hw->regs[0] & ~0x10; _OUTB(port, tmp); hw->regs[0] = tmp; /* update mirror */ for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if (_INB(port) & 0x10) /* verify */ return -EIO; break; case SDLA_S502A: case SDLA_S507: break; default: return -EINVAL; } return 0;}/*============================================================================ * Acknowledge SDLA hardware interrupt. */EXPORT_SYMBOL(sdla_intack);int sdla_intack (sdlahw_t* hw){ unsigned port = hw->port; int tmp; switch (hw->type) { case SDLA_S502E: /* To acknoledge hardware interrupt we have to toggle bit 3 of * control register: \_/ * Note that interrupt control operations on S502E are allowed * only if CPU is enabled (bit 1 of status register is set). */ if (_INB(port) & 0x01) { tmp = hw->regs[0] & ~0x04; _OUTB(port, tmp); tmp |= 0x04; _OUTB(port, tmp); hw->regs[0] = tmp; } else return -EIO; break; case SDLA_S503: if (_INB(port) & 0x04) { tmp = hw->regs[0] & ~0x08; _OUTB(port, tmp); tmp |= 0x08; _OUTB(port, tmp); hw->regs[0] = tmp; } break; case SDLA_S502A: case SDLA_S507: case SDLA_S508: break; default: return -EINVAL; } return 0;}/*============================================================================ * Acknowledge S514 hardware interrupt. */EXPORT_SYMBOL(S514_intack);void S514_intack (sdlahw_t* hw, u32 int_status){ pci_write_config_dword(hw->pci_dev, PCI_INT_STATUS, int_status);}/*============================================================================ * Read the S514 hardware interrupt status. */EXPORT_SYMBOL(read_S514_int_stat);void read_S514_int_stat (sdlahw_t* hw, u32* int_status){ pci_read_config_dword(hw->pci_dev, PCI_INT_STATUS, int_status);}/*============================================================================ * Generate an interrupt to adapter's CPU. */EXPORT_SYMBOL(sdla_intr);int sdla_intr (sdlahw_t* hw){ unsigned port = hw->port; switch (hw->type) { case SDLA_S502A: if (!(_INB(port) & 0x40)) { _OUTB(port, 0x10); /* issue NMI to CPU */ hw->regs[0] = 0x10; } else return -EIO; break; case SDLA_S507: if ((_INB(port) & 0x06) == 0x06) { _OUTB(port + 3, 0); } else return -EIO; break; case SDLA_S508: if (_INB(port + 1) & 0x02) { _OUTB(port, 0x08); } else return -EIO; break; case SDLA_S502E: case SDLA_S503: default: return -EINVAL; } return 0;}/*============================================================================ * Execute Adapter Command. * o Set exec flag. * o Busy-wait until flag is reset. * o Return number of loops made, or 0 if command timed out. */EXPORT_SYMBOL(sdla_exec);int sdla_exec (void* opflag){ volatile unsigned char* flag = opflag; unsigned long tstop; int nloops; if(readb(flag) != 0x00) { printk(KERN_INFO "WANPIPE: opp flag set on entry to sdla_exec\n"); return 0; } writeb(0x01, flag); tstop = SYSTEM_TICK + EXEC_TIMEOUT; for (nloops = 1; (readb(flag) == 0x01); ++ nloops) { unsigned delay = exec_idle; while (-- delay); /* delay */ if (SYSTEM_TICK > tstop) return 0; /* time is up! */ } return nloops;}/*============================================================================ * Read absolute adapter memory. * Transfer data from adapter's memory to data buffer. * * Note: * Care should be taken when crossing dual-port memory window boundary. * This function is not atomic, so caller must disable interrupt if * interrupt routines are accessing adapter shared memory. */EXPORT_SYMBOL(sdla_peek);int sdla_peek (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len){ if (addr + len > hw->memory) /* verify arguments */ return -EINVAL; if(hw->type == SDLA_S514) { /* copy data for the S514 adapter */ peek_by_4 ((unsigned long)hw->dpmbase + addr, buf, len); return 0; } else { /* copy data for the S508 adapter */ unsigned long oldvec = hw->vector; unsigned winsize = hw->dpmsize; unsigned curpos, curlen; /* current offset and block size */ unsigned long curvec; /* current DPM window vector */ int err = 0; while (len && !err) { curpos = addr % winsize; /* current window offset */ curvec = addr - curpos; /* current window vector */ curlen = (len > (winsize - curpos)) ? (winsize - curpos) : len; /* Relocate window and copy block of data */ err = sdla_mapmem(hw, curvec); peek_by_4 ((unsigned long)hw->dpmbase + curpos, buf, curlen); addr += curlen; (char*)buf += curlen; len -= curlen; } /* Restore DPM window position */ sdla_mapmem(hw, oldvec); return err; }}/*============================================================================ * Read data from adapter's memory to a data buffer in 4-byte chunks. * Note that we ensure that the SDLA memory address is on a 4-byte boundary * before we begin moving the data in 4-byte chunks.*/static void peek_by_4 (unsigned long src, void* buf, unsigned len){ /* byte copy data until we get to a 4-byte boundary */ while (len && (src & 0x03)) { *(char *)buf ++ = readb(src ++); len --; } /* copy data in 4-byte chunks */ while (len >= 4) { *(unsigned long *)buf = readl(src); buf += 4; src += 4; len -= 4; } /* byte copy any remaining data */ while (len) { *(char *)buf ++ = readb(src ++); len --; }}/*============================================================================ * Write Absolute Adapter Memory. * Transfer data from data buffer to adapter's memory. * * Note: * Care should be taken when crossing dual-port memory window boundary. * This function is not atomic, so caller must disable interrupt if * interrupt routines are accessing adapter shared memory. */EXPORT_SYMBOL(sdla_poke); int sdla_poke (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len){ if (addr + len > hw->memory) /* verify arguments */ return -EINVAL; if(hw->type == SDLA_S514) { /* copy data for the S514 adapter */ poke_by_4 ((unsigned long)hw->dpmbase + addr, buf, len); return 0; } else { /* copy data for the S508 adapter */ unsigned long oldvec = hw->vector; unsigned winsize = hw->dpmsize; unsigned curpos, curlen; /* current offset and block size */ unsigned long curvec; /* current DPM window vector */ int err = 0; while (len && !err) { curpos = addr % winsize; /* current window offset */ curvec = addr - curpos; /* current window vector */ curlen = (len > (winsize - curpos)) ? (winsize - curpos) : len; /* Relocate window and copy block of data */ sdla_mapmem(hw, curvec); poke_by_4 ((unsigned long)hw->dpmbase + curpos, buf, curlen); addr += curlen; (char*)buf += curlen; len -= curlen; } /* Restore DPM window position */ sdla_mapmem(hw, oldvec); return err; }}/*============================================================================ * Write from a data buffer to adapter's memory in 4-byte chunks. * Note that we ensure that the SDLA memory address is on a 4-byte boundary * before we begin moving the data in 4-byte chunks.*/static void poke_by_4 (unsigned long dest, void* buf, unsigned len){ /* byte copy data until we get to a 4-byte boundary */ while (len && (dest & 0x03)) { writeb (*(char *)buf ++, dest ++); len --; } /* copy data in 4-byte chunks */ while (len >= 4) { writel (*(unsigned long *)buf, dest); dest += 4; buf += 4; len -= 4; } /* byte copy any remaining data */ while (len) { writeb (*(char *)buf ++ , dest ++); len --; }}#ifdef DONT_COMPIPLE_THIS#endif /* DONT_COMPIPLE_THIS *//****** Hardware-Specific Functions *****************************************//*============================================================================ * Detect adapter type. * o if adapter type is specified then call detection routine for that adapter * type. Otherwise call detection routines for every adapter types until * adapter is detected. * * Notes: * 1) Detection tests are destructive! Adapter will be left in shutdown state * after the test. */static int sdla_detect (sdlahw_t* hw){ unsigned port = hw->port; int err = 0; if (!port && (hw->type != SDLA_S514)) return -EFAULT; switch (hw->type) { case SDLA_S502A: if (!detect_s502a(port)) err = -ENODEV; break; case SDLA_S502E: if (!detect_s502e(port)) err = -ENODEV; break; case SDLA_S503: if (!detect_s503(port)) err = -ENODEV; break; case SDLA_S507: if (!detect_s507(port)) err = -ENODEV; break; case SDLA_S508: if (!detect_s508(port)) err = -ENODEV;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -