⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sdladrv.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
 		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 + -