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

📄 sdladrv.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
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;}/*============================================================================ * 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 (*flag) return 0;	/* ???? */	*flag = 1;	tstop = SYSTEM_TICK + EXEC_TIMEOUT;	for (nloops = 1; *flag; ++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){	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;	if (addr + len > hw->memory)	/* verify arguments */		return -EINVAL	;	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);		memcpy(buf, (void *)((u8 *)hw->dpmbase + curpos), curlen);		addr       += curlen;		(char*)buf += curlen;		len        -= curlen;	}	/* Restore DPM window position */	sdla_mapmem(hw, oldvec);	return err;}/*============================================================================ * 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){	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;	if (addr + len > hw->memory)	/* verify arguments */		return -EINVAL	;	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);		memcpy((void*)((u8 *)hw->dpmbase + curpos), buf, curlen);		addr       += curlen;		(char*)buf += curlen;		len        -= curlen;	}	/* Restore DPM window position */	sdla_mapmem(hw, oldvec);	return err;}#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)		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;		break;	default:		if (detect_s502a(port))			hw->type = SDLA_S502A		;		else if (detect_s502e(port))			hw->type = SDLA_S502E		;		else if (detect_s503(port))			hw->type = SDLA_S503		;		else if (detect_s507(port))			hw->type = SDLA_S507		;		else if (detect_s508(port))			hw->type = SDLA_S508		;		else err = -ENODEV;	}	return err;}/*============================================================================ * Autoselect memory region.  * o try all available DMP address options from the top down until success. */static int sdla_autodpm (sdlahw_t* hw){	int i, err = -EINVAL;	unsigned* opt;	switch (hw->type)	{	case SDLA_S502A:		opt = s502a_dpmbase_options;		break;	case SDLA_S502E:	case SDLA_S503:	case SDLA_S508:		opt = s508_dpmbase_options;		break;	case SDLA_S507:		opt = s507_dpmbase_options;		break;	default:		return -EINVAL;	}	for (i = opt[0]; i && err; --i)	{		hw->dpmbase = phys_to_virt(opt[i]);		err = sdla_setdpm(hw);	}	return err;}/*============================================================================ * Set up adapter dual-port memory window.  * o shut down adapter * o make sure that no physical memory exists in this region, i.e entire *   region reads 0xFF and is not writable when adapter is shut down. * o initialize adapter hardware * o make sure that region is usable with SDLA card, i.e. we can write to it *   when adapter is configured. */static int sdla_setdpm (sdlahw_t* hw){	int err;	/* Shut down card and verify memory region */	sdla_down(hw);	if (check_memregion(hw->dpmbase, hw->dpmsize))		return -EINVAL	;	/* Initialize adapter and test on-board memory segment by segment.	 * If memory size appears to be less than shared memory window size,	 * assume that memory region is unusable.	 */	err = sdla_init(hw);	if (err) return err;	if (sdla_memtest(hw) < hw->dpmsize)	/* less than window size */	{		sdla_down(hw);		return -EIO;	}	sdla_mapmem(hw, 0L);	/* set window vector at bottom */	return 0;}/*============================================================================ * Load adapter from the memory image of the SDLA firmware module.  * o verify firmware integrity and compatibility * o start adapter up */static int sdla_load (sdlahw_t* hw, sfm_t* sfm, unsigned len){	int i;	/* Verify firmware signature */	if (strcmp(sfm->signature, SFM_SIGNATURE))	{		printk(KERN_ERR "%s: not SDLA firmware!\n",			modname)		;		return -EINVAL;	}	/* Verify firmware module format version */	if (sfm->version != SFM_VERSION)	{		printk(KERN_ERR			"%s: firmware format %u rejected! Expecting %u.\n",			modname, sfm->version, SFM_VERSION)		;		return -EINVAL;	}	/* Verify firmware module length and checksum */	if ((len - offsetof(sfm_t, image) != sfm->info.codesize) ||		(checksum((void*)&sfm->info,		sizeof(sfm_info_t) + sfm->info.codesize) != sfm->checksum))	{		printk(KERN_ERR "%s: firmware corrupted!\n", modname);		return -EINVAL;	}	/* Announce */	printk(KERN_INFO "%s: loading %s (ID=%u)...\n", modname,		(sfm->descr[0] != '\0') ? sfm->descr : "unknown firmware",		sfm->info.codeid)	;	/* Scan through the list of compatible adapters and make sure our	 * adapter type is listed.	 */	for (i = 0;	     (i < SFM_MAX_SDLA) && (sfm->info.adapter[i] != hw->type);	     ++i)	;	if (i == SFM_MAX_SDLA)	{		printk(KERN_ERR "%s: firmware is not compatible with S%u!\n",			modname, hw->type)		;		return -EINVAL;	}	/* Make sure there is enough on-board memory */	if (hw->memory < sfm->info.memsize)	{		printk(KERN_ERR			"%s: firmware needs %lu bytes of on-board memory!\n",			modname, sfm->info.memsize)		;		return -EINVAL;	}	/* Move code onto adapter */	if (sdla_poke(hw, sfm->info.codeoffs, sfm->image, sfm->info.codesize))	{		printk(KERN_ERR "%s: failed to load code segment!\n",			modname)		;		return -EIO;	}	/* Prepare boot-time configuration data and kick-off CPU */	sdla_bootcfg(hw, &sfm->info);	if (sdla_start(hw, sfm->info.startoffs))	{		printk(KERN_ERR "%s: Damn... Adapter won't start!\n",			modname)		;		return -EIO;	}	/* position DPM window over the mailbox and enable interrupts */        if (sdla_mapmem(hw, sfm->info.winoffs) || sdla_inten(hw))	{		printk(KERN_ERR "%s: adapter hardware failure!\n",			modname)		;		return -EIO;	}	hw->fwid = sfm->info.codeid;		/* set firmware ID */	return 0;}/*============================================================================ * Initialize SDLA hardware: setup memory window, IRQ, etc. */static int sdla_init (sdlahw_t* hw){	int i;	for (i = 0; i < SDLA_MAXIORANGE; ++i)		hw->regs[i] = 0	;	switch (hw->type)	{	case SDLA_S502A: return init_s502a(hw);	case SDLA_S502E: return init_s502e(hw);	case SDLA_S503:  return init_s503(hw);	case SDLA_S507:  return init_s507(hw);	case SDLA_S508:  return init_s508(hw);	}	return -EINVAL;}/*============================================================================ * Test adapter on-board memory. * o slide DPM window from the bottom up and test adapter memory segment by *   segment. * Return adapter memory size. */static unsigned long sdla_memtest (sdlahw_t* hw){	unsigned long memsize;	unsigned winsize;	for (memsize = 0, winsize = hw->dpmsize;	     !sdla_mapmem(hw, memsize) &&		(test_memregion(hw->dpmbase, winsize) == winsize)	     ;	     memsize += winsize)	;	hw->memory = memsize;	return memsize;}/*============================================================================ * Prepare boot-time firmware configuration data. * o position DPM window * o initialize configuration data area */static int sdla_bootcfg (sdlahw_t* hw, sfm_info_t* sfminfo){	unsigned char* data;	if (!sfminfo->datasize) return 0;	/* nothing to do */	if (sdla_mapmem(hw, sfminfo->dataoffs) != 0)		return -EIO	;	data = (void*)((u8 *)hw->dpmbase + (sfminfo->dataoffs - hw->vector));	memset(data, 0, sfminfo->datasize);	data[0x00] = make_config_byte(hw);	switch (sfminfo->codeid)	{	case SFID_X25_502:	case SFID_X25_508:		data[0x01] = 3;			/* T1 timer */		data[0x03] = 10;		/* N2 */		data[0x06] = 7;			/* HDLC window size */		data[0x0B] = 1;			/* DTE */		data[0x0C] = 2;			/* X.25 packet window size */		*(short*)&data[0x0D] = 128;	/* default X.25 data size */		*(short*)&data[0x0F] = 128;	/* maximum X.25 data size */		break;	}	return 0;}/*============================================================================ * Prepare configuration byte identifying adapter type and CPU clock rate. */static unsigned char make_config_byte (sdlahw_t* hw){	unsigned char byte = 0;	switch (hw->pclk)	{		case 5000:  byte = 0x01; break;		case 7200:  byte = 0x02; break;		case 8000:  byte = 0x03; break;		case 10000: byte = 0x04; break;		case 16000: byte = 0x05; break;	}	switch (hw->type)	{		case SDLA_S502E: byte |= 0x80; break;		case SDLA_S503:  byte |= 0x40; break;	}	return byte;}/*============================================================================ * Start adapter's CPU. * o calculate a pointer to adapter's cold boot entry point * o position DPM window * o place boot instruction (jp addr) at cold boot entry point * o start CPU */static int sdla_start (sdlahw_t* hw, unsigned addr){	unsigned port = hw->port;	unsigned char *bootp;	int err, tmp, i;	if (!port) return -EFAULT;	switch (hw->type)	{	case SDLA_S502A:		bootp = hw->dpmbase;		bootp += 0x66;		break;	case SDLA_S502E:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -