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

📄 simp911x.c

📁 SMSC 9118 Driver for linux
💻 C
📖 第 1 页 / 共 5 页
字号:
//  through register_netdev, to Simp911x_init

struct net_device SIMP911X[MAX_INSTANCES];

#define DRIVER_VERSION (0x00000111UL)

//entry point for loading the module
int Simp911x_init_module(void)
{
	int result=0;
	int device_present=0;
	DWORD index=0;
	SMSC_TRACE("--> init_module()");
#ifdef USE_PHY_WORK_AROUND
	SMSC_TRACE("Simple Driver Version = %lX.%02lX, with phy work around",
		(DRIVER_VERSION>>8),(DRIVER_VERSION&0xFFUL));
#else
	SMSC_TRACE("Simple Driver Version = %lX.%02lX",
		(DRIVER_VERSION>>8),(DRIVER_VERSION&0xFFUL));
#endif
	SMSC_TRACE("Compiled: %s, %s",__DATE__,__TIME__);

	if(lan_base[0]!=0) {
		for(index=0;index<MAX_INSTANCES;index++) {
			SIMP911X[index].priv=NULL;
			SIMP911X[index].init=Simp911x_init;
			if(lan_base[index]!=0) {
				strcpy(SIMP911X[index].name,"eth%d");
				gRegistrationIndex=index;
				result=register_netdev(&(SIMP911X[index]));
				if(result) {
					SMSC_WARNING("error %i registering device",result);
					registered[index]=0;
				} else {
					device_present=1;
					registered[index]=1;
					SMSC_TRACE("  Interface Name = \"%s\"",SIMP911X[index].name);
				}
			} else {
				registered[index]=0;
			}
		}
	} else {
		SMSC_WARNING("Must supply lan_base and irq.");
	}
	SMSC_TRACE("<-- init_module()");
	return device_present ? 0 : -ENODEV;
}

//entry point for unloading the module
void Simp911x_cleanup_module(void)
{
	DWORD index=0;
	SMSC_TRACE("--> cleanup_module()");
	for(index=0;index<MAX_INSTANCES;index++) {
		if(SIMP911X[index].priv!=NULL) {
			kfree(SIMP911X[index].priv);
		}
		if(registered[index]) {
			unregister_netdev(&(SIMP911X[index]));
		}
	}
	SMSC_TRACE("<-- cleanup_module()");
}

//entry point for initializing the driver
int Simp911x_init(struct net_device *dev)
{
	DWORD dwIdRev=0UL;
	PPRIVATE_DATA privateData=NULL;
	int result=-ENODEV;
	SMSC_TRACE("-->Simp911x_init(dev=0x%08lX)",(DWORD)dev);

	if(dev==NULL) {
		SMSC_WARNING("Simp911x_init(dev==NULL)");
		result=-EFAULT;
		goto DONE;
	}

	SMSC_TRACE("Device Instance Index = %ld",gRegistrationIndex);
	SMSC_TRACE("Driver Parameters");
	SMSC_TRACE("  lan_base         = 0x%08lX",lan_base[gRegistrationIndex]);
	SMSC_TRACE(    "  irq              = %ld",irq[gRegistrationIndex]);
	if(mac_addr_hi16[gRegistrationIndex]==0xFFFFFFFFUL) {
		SMSC_TRACE("  mac_addr_hi16    = 0x%08lX, will attempt to read from LAN911x",
			mac_addr_hi16[gRegistrationIndex]);
		SMSC_TRACE("  mac_addr_lo32    = 0x%08lX, will attempt to read from LAN911x",
			mac_addr_lo32[gRegistrationIndex]);
	} else {
		if(mac_addr_hi16[gRegistrationIndex]&0xFFFF0000UL) {
			//The high word is reserved
			SMSC_WARNING("  mac_addr_hi16 = 0x%08lX, reserved bits are high.",
				mac_addr_hi16[gRegistrationIndex]);
			mac_addr_hi16[gRegistrationIndex]&=0x0000FFFFUL;
			SMSC_WARNING("    reseting to mac_addr_hi16 = 0x%08lX",
				mac_addr_hi16[gRegistrationIndex]);
		}
		if(mac_addr_lo32[gRegistrationIndex]&0x00000001UL) {
			//bit 0 is the I/G bit
			SMSC_WARNING("  mac_addr_lo32 = 0x%08lX, I/G bit is set.",
				mac_addr_lo32[gRegistrationIndex]);
			mac_addr_lo32[gRegistrationIndex]&=0xFFFFFFFEUL;
			SMSC_WARNING("    reseting to mac_addr_lo32 = 0x%08lX",
				mac_addr_lo32[gRegistrationIndex]);			
		}
		SMSC_TRACE("  mac_addr_hi16    = 0x%08lX",
			mac_addr_hi16[gRegistrationIndex]);
		SMSC_TRACE("  mac_addr_lo32    = 0x%08lX",
			mac_addr_lo32[gRegistrationIndex]);
	}
	SMSC_TRACE(    "  debug_mode       = 0x%08lX",debug_mode);
	if(phy_addr[gRegistrationIndex]==0xFFFFFFFFUL) {
		SMSC_TRACE("  phy_addr         = 0xFFFFFFFF, Use internal phy");
	} else if(phy_addr[gRegistrationIndex]<=31) {
		SMSC_TRACE("  phy_addr         = 0x%08lX, use this address for external phy",
			phy_addr[gRegistrationIndex]);
	} else {
		SMSC_TRACE("  phy_addr         = 0x%08lX, auto detect external phy",
			phy_addr[gRegistrationIndex]);
	}
	if(dev->priv!=NULL) {
		SMSC_WARNING("dev->priv!=NULL, going to overwrite pointer");
	}
	dev->priv=kmalloc(sizeof(PRIVATE_DATA),GFP_KERNEL);
	if(dev->priv==NULL) {
		SMSC_WARNING("Unable to allocate PRIVATE_DATA");
		result=-ENOMEM;
		goto DONE;
	}
	memset(dev->priv,0,sizeof(PRIVATE_DATA));
	privateData=(PPRIVATE_DATA)(dev->priv);

	if(lan_base[gRegistrationIndex]==0UL) {
		SMSC_WARNING("lan_base==0x00000000");
		result=-ENODEV;
		goto DONE;
	}

	if(check_mem_region(lan_base[gRegistrationIndex],LAN_REGISTER_EXTENT)!=0) {
		SMSC_WARNING("  Memory Region specified (0x%08lX to 0x%08lX) is not available.",
			lan_base[gRegistrationIndex],lan_base[gRegistrationIndex]+LAN_REGISTER_EXTENT-1);
		result=-ENOMEM;
		goto DONE;
	}
	
	privateData->dwLanBase=lan_base[gRegistrationIndex];
	privateData->dwInstanceIndex=gRegistrationIndex;
	dwIdRev=Lan_GetRegDW(ID_REV);
	if(HIWORD(dwIdRev)==LOWORD(dwIdRev)) {
		//this may mean the chip is set for 32 bit 
		//  while the bus is reading as 16 bit
UNKNOWN_CHIP:
		SMSC_WARNING("LAN911x NOT Identified, dwIdRev==0x%08lX",dwIdRev);
		result=-ENODEV;
		goto DONE;
	}
	switch(dwIdRev&0xFFFF0000UL) {
	case 0x01180000UL:
		SMSC_TRACE("LAN9118 identified, dwIdRev==0x%08lX",dwIdRev);break;
	case 0x01170000UL:
		SMSC_TRACE("LAN9117 identified, dwIdRev==0x%08lX",dwIdRev);break;
	case 0x01160000UL:
		SMSC_TRACE("LAN9116 identified, dwIdRev==0x%08lX",dwIdRev);break;
	case 0x01150000UL:
		SMSC_TRACE("LAN9115 identified, dwIdRev==0x%08lX",dwIdRev);break;
	case 0x01120000UL:
		SMSC_TRACE("LAN9112 identified, dwIdRev==0x%08lX",dwIdRev);break;
	default:
		goto UNKNOWN_CHIP;
	}
	privateData->dwIdRev=dwIdRev;

	if((dwIdRev&0x0000FFFFUL)==0UL) {
		SMSC_WARNING("This driver is not intended for this chip revision");
	}

	ether_setup(dev);
	dev->open=				Simp911x_open;
	dev->stop=				Simp911x_stop;
	dev->hard_start_xmit=	Simp911x_hard_start_xmit;
	dev->get_stats=			Simp911x_get_stats;
	dev->set_multicast_list=Simp911x_set_multicast_list;
	dev->flags|=IFF_MULTICAST;

	SET_MODULE_OWNER(dev);

	privateData->dev=dev;

	result=0;
    
DONE:
	if(result!=0) {
		//something went wrong, perform clean up
		if(dev!=NULL) {
			if(dev->priv!=NULL) {
				kfree(dev->priv);
				dev->priv=NULL;
			}
		}
	}
	SMSC_TRACE("<--Simp911x_init(), result=%d",result);
	return result;
}

//entry point for starting/opening the interface
int Simp911x_open(struct net_device *dev)
{
	int result=-ENODEV;
	PPRIVATE_DATA privateData=NULL;
	BOOLEAN acquired_mem_region=FALSE;
	BOOLEAN acquired_isr=FALSE;
	char temp_name[25];
	SMSC_TRACE("-->Simp911x_open(dev=0x%08lX)",(DWORD)dev);
	if(dev==NULL) {
		SMSC_WARNING("Simp911x_open(dev==NULL)");
		result=-EFAULT;
		goto DONE;
	}
	privateData=(PPRIVATE_DATA)(dev->priv);
	if(privateData==NULL) {
		SMSC_WARNING("Simp911x_open(privateData==NULL)");
		result=-EFAULT;
		goto DONE;
	}

	//get memory region
	if(check_mem_region(privateData->dwLanBase,LAN_REGISTER_EXTENT)!=0)
	{
		SMSC_WARNING("Device memory is already in use.");
		result=-ENOMEM;
		goto DONE;
	}

	sprintf(temp_name,"SIMP_LAN911X_%ld",privateData->dwInstanceIndex);
	request_mem_region(privateData->dwLanBase,LAN_REGISTER_EXTENT,temp_name);
	acquired_mem_region=TRUE;

	//initialize the LAN911x
	{
		const DWORD dwIntCfg=(((DWORD)22UL)<<24);//set interrupt deassertion to 220uS
		//dwIntCfg|=INT_CFG_IRQ_POL_;  //use this line to set IRQ_POL bit
		//dwIntCfg|=INT_CFG_IRQ_TYPE_; //use this line to set IRQ_TYPE bit
		if(!Lan_Initialize(privateData,dwIntCfg)) {
			goto DONE;
		}
	}

	sprintf(temp_name,"SIMP_LAN911X_ISR_%ld",privateData->dwInstanceIndex);
	if(request_irq(
		irq[privateData->dwInstanceIndex],
		Simp911x_ISR,
		SA_INTERRUPT,
		temp_name,
		privateData)!=0)
	{
		result=-ENODEV;
		goto DONE;
	}
	acquired_isr=TRUE;

	//must now test the IRQ connection to the ISR
	SMSC_TRACE("Testing ISR using IRQ %ld",irq[privateData->dwInstanceIndex]);
	{
		DWORD dwTimeOut=1000;
		privateData->RequestIrqDisable=FALSE;
		privateData->SoftwareInterruptSignal=FALSE;
		Lan_SetBitsDW(INT_EN,INT_EN_SW_INT_EN_);
		do {
			udelay(10);
			dwTimeOut--;
		} while((dwTimeOut)&&(!(privateData->SoftwareInterruptSignal)));
		if(!(privateData->SoftwareInterruptSignal)) {
			SMSC_WARNING("ISR failed signaling test");
			result=-ENODEV;
			goto DONE;
		}
	}
	SMSC_TRACE("ISR passed test using IRQ %ld",irq[privateData->dwInstanceIndex]);

	Mac_Initialize(privateData);
	{//get mac address
		DWORD dwHigh16=0;
		DWORD dwLow32=0;
		//Because this is part of the single threaded initialization
		//  path there is no need to acquire the MacPhyAccessLock
		if(mac_addr_hi16[privateData->dwInstanceIndex]==0xFFFFFFFF) {
			dwHigh16=Mac_GetRegDW(privateData,ADDRH);
			dwLow32=Mac_GetRegDW(privateData,ADDRL);
			if((dwHigh16==0x0000FFFFUL)&&(dwLow32==0xFFFFFFFF))
			{
				dwHigh16=0x00000070UL;
				dwLow32=0x110F8000UL;
				Mac_SetRegDW(privateData,ADDRH,dwHigh16);
				Mac_SetRegDW(privateData,ADDRL,dwLow32);
				SMSC_TRACE("Mac Address is set by default to 0x%04lX%08lX",
					dwHigh16,dwLow32);
			} else {
				SMSC_TRACE("Mac Address is read from LAN911x as 0x%04lX%08lX",
					dwHigh16,dwLow32);
			}
		} else {
			dwHigh16=mac_addr_hi16[privateData->dwInstanceIndex];
			dwLow32=mac_addr_lo32[privateData->dwInstanceIndex];
			Mac_SetRegDW(privateData,ADDRH,dwHigh16);
			Mac_SetRegDW(privateData,ADDRL,dwLow32);
			SMSC_TRACE("Mac Address is set by parameter to 0x%04lX%08lX",
				dwHigh16,dwLow32);
		}
		dev->dev_addr[0]=LOBYTE(LOWORD(dwLow32));
		dev->dev_addr[1]=HIBYTE(LOWORD(dwLow32));
		dev->dev_addr[2]=LOBYTE(HIWORD(dwLow32));
		dev->dev_addr[3]=HIBYTE(HIWORD(dwLow32));
		dev->dev_addr[4]=LOBYTE(LOWORD(dwHigh16));
		dev->dev_addr[5]=HIBYTE(LOWORD(dwHigh16));
	}

	netif_carrier_off(dev);
	if(!Phy_Initialize(
		privateData,
		phy_addr[privateData->dwInstanceIndex]))
	{
		SMSC_WARNING("Failed to initialize Phy");
		result=-ENODEV;
		goto DONE;
	}

	Tx_Initialize(privateData);
	Rx_Initialize(privateData);

#ifndef LINUX_2_6_OR_NEWER
	MOD_INC_USE_COUNT;
#endif
	netif_start_queue(dev);


	result=0;

DONE:
	if(result!=0) {
#ifndef LINUX_2_6_OR_NEWER
		MOD_DEC_USE_COUNT;
#endif
		if((acquired_isr)&&(privateData!=NULL)) {
			free_irq(irq[privateData->dwInstanceIndex],privateData);
		}
		if((acquired_mem_region)&&(privateData!=NULL)) {
			release_mem_region(
				privateData->dwLanBase,
				LAN_REGISTER_EXTENT);
		}
	}
	SMSC_TRACE("<--Simp911x_open, result=%d",result);
	return result;
}

//entry point for stopping the interface
int Simp911x_stop(struct net_device *dev)
{
	int result=0;
	PPRIVATE_DATA privateData=NULL;
	SMSC_TRACE("-->Simp911x_stop(dev=0x%08lX)",(DWORD)dev);
	if(dev==NULL) {
		SMSC_WARNING("Simp911x_stop(dev==NULL)");
		result=-EFAULT;
		goto DONE;
	}
	privateData=(PPRIVATE_DATA)(dev->priv);
	if(privateData==NULL) {
		SMSC_WARNING("Simp911x_stop(privateData==NULL)");
		result=-EFAULT;
		goto DONE;
	}

	privateData->StopLinkPolling=TRUE;
	del_timer_sync(&(privateData->LinkPollingTimer));

	{//Disable IRQ safely, by using the software interrupt
		// to do it in the ISR itself.
		DWORD dwTimeOut=1000;
		privateData->RequestIrqDisable=TRUE;

⌨️ 快捷键说明

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