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

📄 realtekr1000.cpp

📁 Mac OS X 下的网卡驱动
💻 CPP
📖 第 1 页 / 共 4 页
字号:
/* This driver based on R1000 Linux Driver for Realtek controllers. * It's not supported by Realtek company, so use it for your own risk. * 2006 (c) Dmitri Arekhta (DaemonES@gmail.com) *  * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. *  * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. *  * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. * ***************************************************************** * * MODIFIED by PSYSTAR, 2008 -- (Rudy Pedraza) * -- all changes released under GPL as required * -- changes made to code are copyright PSYSTAR Corporation, 2008 **** Enhancement Log * - added sleep/wake DHCP fix for * - changed tx/rx interrupt handling, 2x speedup * - added support for multiple NIC's, driver didnt play nice before * - fixed com.apple.kernel & com.apple.kpi dependencies, you cant use both (warning now, future error) * - cleaned up Info.plist, fixed matching */#include "RealtekR1000.h"#define BaseClass IOEthernetController#define RELEASE(x) do { if(x) { (x)->release(); (x) = 0; } } while(0)OSDefineMetaClassAndStructors(RealtekR1000, IOEthernetController)/* Some additional structs */const static struct RtlChipInfo {	const char *name;	u8 mcfg;		 /* depend on documents of Realtek */	u32 RxConfigMask; 	/* should clear the bits supported by this chip */} rtl_chip_info[] = {	{ "RTL8169",			MCFG_METHOD_1,	0xff7e1880 },	{ "RTL8169S/8110S",		MCFG_METHOD_2,  0xff7e1880 },	{ "RTL8169S/8110S",		MCFG_METHOD_3,  0xff7e1880 },	{ "RTL8169SB/8110SB",	MCFG_METHOD_4,  0xff7e1880 },	{ "RTL8169SC/8110SC",	MCFG_METHOD_5,  0xff7e1880 },	{ "RTL8168B/8111B",		MCFG_METHOD_11, 0xff7e1880 },	{ "RTL8168B/8111B",		MCFG_METHOD_12, 0xff7e1880 },	{ "RTL8101E",			MCFG_METHOD_13, 0xff7e1880 },	{ "RTL8100E",			MCFG_METHOD_14, 0xff7e1880 },	{ "RTL8100E",			MCFG_METHOD_15, 0xff7e1880 },	{ 0 }};/* Maximum events (Rx packets, etc.) to handle at each interrupt. */int RealtekR1000::max_interrupt_work = 20;/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).   The RTL chips use a 64 element hash table based on the Ethernet CRC.  */int RealtekR1000::multicast_filter_limit = 32;const unsigned int RealtekR1000::ethernet_polynomial = 0x04c11db7U;static const u16 r1000_intr_mask = LinkChg | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK ;static const unsigned int r1000_rx_config = (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift) | 0x0000000E;/* * Initialization of driver instance, * i.e. resources allocation and so on.*/bool RealtekR1000::init(OSDictionary *properties){	DLog("RealtekR1000::init(OSDictionary *properties)\n");	if (BaseClass::init(properties) == false) return false;		pciDev = NULL;	mmioBase = NULL;	workLoop = NULL;	intSource = NULL;    timerSource = NULL;    netStats = NULL;    etherStats = NULL;	transmitQueue = NULL;    netif = NULL;	enabled = false;	forcedPio = false;	isInitialized = false;	enabledForKDP = enabledForBSD = false;			return true;}/* * Calling before destroing driver instance. * Frees all allocated resources.*/void RealtekR1000::free(){	DLog("RealtekR1000::free()");		//free resource of base instance	if (intSource && workLoop)	{		//Detaching interrupt source from work loop		workLoop->removeEventSource(intSource);	}  	RELEASE(netif);    RELEASE(intSource);    RELEASE(timerSource);    RELEASE(mmioBase);    RELEASE(pciDev);    RELEASE(workLoop);		FreeDescriptorsMemory();		BaseClass::free();} /* * Starting driver.*/bool RealtekR1000::start(IOService *provider){	bool success = false;	DLog("::start(IOService *%08x)\n",  provider);		do	{		pciDev = OSDynamicCast(IOPCIDevice, provider);		if (!pciDev)		{			DLog("::start: Failed to cast provider\n");			break;		}		if (BaseClass::start(pciDev) == false)		{			DLog("::start: Failed super::start returned false\n");			break;		}		pciDev->retain();					if(pciDev->open(this) == false)		{			DLog("::start: Failed to open PCI Device/Nub\n");			break;		}				chipset = 5; //Assuming RTL8168/8111 by default				//Adding Mac OS X PHY's		mediumDict = OSDictionary::withCapacity(MEDIUM_INDEX_COUNT + 1);		OSAddNetworkMedium(kIOMediumEthernetAuto, 0, MEDIUM_INDEX_AUTO);			OSAddNetworkMedium(kIOMediumEthernet10BaseT | kIOMediumOptionHalfDuplex, 10 * MBit, MEDIUM_INDEX_10HD);		OSAddNetworkMedium(kIOMediumEthernet10BaseT | kIOMediumOptionFullDuplex, 10 * MBit, MEDIUM_INDEX_10FD);		OSAddNetworkMedium(kIOMediumEthernet100BaseTX | kIOMediumOptionHalfDuplex, 100 * MBit, MEDIUM_INDEX_100HD);		OSAddNetworkMedium(kIOMediumEthernet100BaseTX | kIOMediumOptionFullDuplex, 100 * MBit, MEDIUM_INDEX_100FD);			OSAddNetworkMedium(kIOMediumEthernet1000BaseTX | kIOMediumOptionHalfDuplex, 1000 * MBit, MEDIUM_INDEX_1000HD);		OSAddNetworkMedium(kIOMediumEthernet1000BaseTX | kIOMediumOptionFullDuplex, 1000 * MBit, MEDIUM_INDEX_1000FD);				if (!publishMediumDictionary(mediumDict))		{			DLog("::start: Failed publishMediumDictionary returned false");			break;		}				if (!R1000ProbeAndStartBoard())		{			DLog("::start: Failed R1000ProbeAndStartBoard returned false");			break;		}				if (!AllocateDescriptorsMemory())		{			DLog("::start: Failed AllocateDescriptorsMemory returned false");			break;		}				if (!R1000InitEventSources(provider))		{			DLog("::start: Failed R1000InitEventSources returned false");			break;		}				success = true;	}	while ( false );			// Close our provider, it will be re-opened on demand when	// our enable() is called by a client.	if(pciDev)	{		pciDev->close(this);	}		do	{		// break if we've had an error before this	    if ( false == success )		{			break;		}		//Attaching dynamic link layer		if (false == attachInterface((IONetworkInterface**)&netif, false))		{			DLog("::start: Failed 'attachInterface' in attaching to data link layer\n");			break;		}		netif->registerService();		success = true;	}	while ( false );		// set isInitialized status	isInitialized = true;		DLog("::start: returning '%d'\n",success);	return success;}/* * Stopping driver.*/void RealtekR1000::stop(IOService *provider){	DLog("RealtekR1000::stop(IOService *provider)\n");	detachInterface(netif);	R1000StopBoard();	BaseClass::stop(provider);}bool RealtekR1000::OSAddNetworkMedium(ulong type, UInt32 bps, ulong index){	IONetworkMedium *medium;		medium = IONetworkMedium::medium( type, bps, 0, index );	if (!medium) 	{		DLog("Couldn't allocate medium\n");				return false;	}	if (!IONetworkMedium::addMedium(mediumDict, medium)) 	{		DLog("Couldn't add medium\n");		return false;	}	mediumTable[index] = medium;	return true;}bool RealtekR1000::increaseActivationLevel(UInt32 level){	bool ret = false;	switch (level)	{	case kActivationLevelKDP:		if (!pciDev) break;		pciDev->open(this);				// PHY medium selection.		const IONetworkMedium *medium = getSelectedMedium();		if (!medium)		{			DLog("Selected medium is NULL, forcing to autonegotiation\n");			medium = mediumTable[MEDIUM_INDEX_AUTO];		}		else		{			DLog("Selected medium index %d", medium->getIndex());		}				selectMedium(medium);		timerSource->setTimeoutMS(TX_TIMEOUT);		ret = true;		break;	case kActivationLevelBSD:		if (!R1000OpenAdapter()) break;		transmitQueue->setCapacity(kTransmitQueueCapacity);		transmitQueue->start();				ret = true;		break;	}		return ret;}bool RealtekR1000::decreaseActivationLevel(UInt32 level){	switch (level)	{	case kActivationLevelKDP:		timerSource->cancelTimeout();				if (pciDev) pciDev->close(this);		break;	case kActivationLevelBSD:		transmitQueue->stop();			transmitQueue->setCapacity(0);		transmitQueue->flush();		R1000CloseAdapter();		break;	}		return true;}bool RealtekR1000::setActivationLevel(UInt32 level){    bool success = false;	DLog("setActivationLevel %d\n", level);    if (activationLevel == level) return true;    for ( ; activationLevel > level; activationLevel--)     {        if ((success = decreaseActivationLevel(activationLevel)) == false)            break;    }    for ( ; activationLevel < level; activationLevel++ )     {        if ((success = increaseActivationLevel(activationLevel+1)) == false)            break;    }    return success;}/* * A request from an interface client to enable the controller.*/IOReturn RealtekR1000::enable(IONetworkInterface *netif){	DLog("RealtekR1000::enable(IONetworkInterface *netif)\n");		if (enabledForBSD) return kIOReturnSuccess;		enabledForBSD = setActivationLevel(kActivationLevelBSD);	if (enabledForBSD)	{		this->enabled = true;		return kIOReturnSuccess;	}	else return kIOReturnIOError;}/* * A request from an interface client to disable the controller.*/IOReturn RealtekR1000::disable(IONetworkInterface *netif){	enabledForBSD = false;		setActivationLevel(enabledForKDP ? kActivationLevelKDP : kActivationLevelNone);		this->enabled = false;	return kIOReturnSuccess;}/* * Transmits an output packet. * packet - an mbuf chain containing the output packet to be sent on the network. * param - a parameter provided by the caller.*/UInt32 RealtekR1000::outputPacket(mbuf_t m, void *param){	//DLog("RedaltekR1000::outputPacket(mbuf_t m, void *param)\n");		int entry = cur_tx % NUM_TX_DESC;	int buf_len = 60;				if ((OSSwapLittleToHostInt32(TxDescArray[entry].status) & OWNbit) == 0)	{			if (mbuf_pkthdr_len(m) <= tx_pkt_len) buf_len = mbuf_pkthdr_len(m);		else		{			DLog("Tx Packet size is too big, droping\n");			freePacket(m);			return kIOReturnOutputDropped;		}				Tx_skbuff[entry] = m;																							TxDescArray[entry].buf_addr = OSSwapHostToLittleInt32(Tx_skbuff_Dma[entry]);				uchar *data_ptr = Tx_dbuff[entry];		ulong pkt_snd_len = 0;		mbuf_t cur_buf = m;				do		{			if (mbuf_data(cur_buf))	bcopy(mbuf_data(cur_buf), data_ptr, mbuf_len(cur_buf));			data_ptr += mbuf_len(cur_buf);			pkt_snd_len += mbuf_len(cur_buf);		}		while(((cur_buf = mbuf_next(cur_buf)) != NULL) && ((pkt_snd_len + mbuf_len(cur_buf)) <= buf_len));		buf_len = pkt_snd_len;						if (entry != (NUM_TX_DESC - 1))		{			TxDescArray[entry].status = OSSwapHostToLittleInt32((OWNbit | FSbit | LSbit) | buf_len);		}		else		{			TxDescArray[entry].status = OSSwapHostToLittleInt32((OWNbit | EORbit | FSbit | LSbit) | buf_len);		}				WriteMMIO8 ( TxPoll, 0x40);		//set polling bit		cur_tx++;				//DLog("mbuf_len %d, packet_len %d\n", mbuf_len(m), mbuf_pkthdr_len(m));		//DLog("cur_tx %d, dirty_tx %d, buf_len %d\n", cur_tx, dirty_tx, buf_len, mbuf_data(m), mbuf_data_to_physical(mbuf_data(m)));	}	else 	{		DLog("TX_RING_IS_FULL stalling\n");		return kIOReturnOutputStall;	}	/*if ((cur_tx - NUM_TX_DESC) == dirty_tx)	{		transmitQueue->stop();	}	else	{		transmitQueue->start();	}*/	return kIOReturnOutputSuccess;}void RealtekR1000::getPacketBufferConstraints(IOPacketBufferConstraints *constraints) const{	DLog("RealtekR1000::getPacketBufferConstraints(IOPacketBufferConstraints *constraints) const\n");	constraints->alignStart = kIOPacketBufferAlign4;	constraints->alignLength = kIOPacketBufferAlign4;}IOOutputQueue *RealtekR1000::createOutputQueue(){	DLog("RealtekR1000::createOutputQueue()\n");	//Sharing one event source with transmith/receive handles	return IOGatedOutputQueue::withTarget(this, getWorkLoop());}/* * Returns a string describing the vendor of the network controller. The caller is responsible for releasing the string object returned.*/const OSString *RealtekR1000::newVendorString() const{	DLog("RealtekR1000::newVendorString() const\n");	return OSString::withCString("Realtek");}/* * Returns a string describing the model of the network controller. The caller is responsible for releasing the string object returned.*/const OSString *RealtekR1000::newModelString() const{	DLog("RealtekR1000::newModelString() const\n");	return OSString::withCString(rtl_chip_info[chipset].name);}/* * A client request to change the medium selection. * This method is called when a client issues a command for the controller to change its  * current medium selection. The implementation must call setSelectedMedium() after the change  * has occurred. This method call is synchronized by the workloop's gate.*/IOReturn RealtekR1000::selectMedium(const IONetworkMedium *medium){	DLog("RealtekR1000::selectMedium(const IONetworkMedium *medium)\n");	DLog("index %d\n", medium->getIndex());	if (medium) 	{		switch (medium->getIndex())		{		case MEDIUM_INDEX_AUTO:			R1000SetMedium(SPEED_100, DUPLEX_FULL, AUTONEG_ENABLE);			break;		case MEDIUM_INDEX_10HD:			R1000SetMedium(SPEED_10, DUPLEX_HALF, AUTONEG_DISABLE);			break;		case MEDIUM_INDEX_10FD:			R1000SetMedium(SPEED_10, DUPLEX_FULL, AUTONEG_DISABLE);			break;		case MEDIUM_INDEX_100HD:			R1000SetMedium(SPEED_100, DUPLEX_HALF, AUTONEG_DISABLE);			break;		case MEDIUM_INDEX_100FD:			R1000SetMedium(SPEED_100, DUPLEX_FULL, AUTONEG_DISABLE);

⌨️ 快捷键说明

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