📄 kernelnetworkdriver_amdpcnet.c
字号:
#include "kernelBusPCI.h"#include "kernelLock.h"#include "kernelNetwork.h"#include "kernelProcessorX86.h"#include "kernelLog.h"#include "kernelMalloc.h"#include "kernelMemoryManager.h"#include "kernelPageManager.h"#include "kernelParameters.h"#include "kernelMiscFunctions.h"#include "kernelInterrupt.h"#include "kernelError.h"#include "kernelNetworkDriver_AmdPCNetRegisters.h"#include <errno.h>#include <stddef.h>/*#define NET_TRANSMIT_BUFFER_NUMBER 4#define NET_TRANSMIT_BUFFER_SIZE 1536#define NET_TOTAL_TRANSMIT_BUFFER_SIZE NET_TRANSMIT_BUFFER_NUMBER * NET_TRANSMIT_BUFFER_SIZE #define NET_RECEIVE_BUFFER_NUMBER 4#define NET_RECEIVE_BUFFER_SIZE 1536#define NET_TOTAL_RECEIVE_BUFFER_SIZE NET_RECEIVE_BUFFER_NUMBER * NET_RECEIVE_BUFFER_SIZE*/#define PCNET32_LOG_TX_BUFFERS 2#define PCNET32_LOG_RX_BUFFERS 2#define TX_RING_SIZE (1 << (PCNET32_LOG_TX_BUFFERS))#define TX_RING_MOD_MASK (TX_RING_SIZE - 1)#define TX_RING_LEN_BITS ((PCNET32_LOG_TX_BUFFERS) << 12)#define RX_RING_SIZE (1 << (PCNET32_LOG_RX_BUFFERS))#define RX_RING_MOD_MASK (RX_RING_SIZE - 1)#define RX_RING_LEN_BITS ((PCNET32_LOG_RX_BUFFERS) << 4)#define NET_TRANSMIT_BUFFER_NUMBER TX_RING_SIZE#define NET_TRANSMIT_BUFFER_SIZE 1536#define NET_TOTAL_TRANSMIT_BUFFER_SIZE NET_TRANSMIT_BUFFER_NUMBER * NET_TRANSMIT_BUFFER_SIZE #define NET_RECEIVE_BUFFER_NUMBER RX_RING_SIZE#define NET_RECEIVE_BUFFER_SIZE 1536#define NET_TOTAL_RECEIVE_BUFFER_SIZE NET_RECEIVE_BUFFER_NUMBER * NET_RECEIVE_BUFFER_SIZE#define NET_DEBUGstatic int kernelNetworkDriverInitialize_AmdPCNet(kernelNetworkInterface * nic);static int kernelNetworkDriverDestroy_AmdPCNet(kernelNetworkInterface * nic);static int kernelNetworkDriverHandleInterrupt_AmdPCNet(void * data);static int kernelNetworkDriverTransmit_AmdPCNet(kernelNetworkInterface * nic, void * data, int length);//one element of the transmit ringtypedef struct{ unsigned long bufferBaseAddress; signed short bufferLength; signed short statusBits; unsigned long miscBits; unsigned long reserved;} amdPCNetTransmitDescriptor;//One element of the receive ringtypedef struct { //the physical address of the buffer this descriptor points to unsigned long bufferBaseAddress; //the two's complement of the buffer length signed short bufferLength; //some bits to set extra options signed short statusBits; //length of the received message unsigned long messageLength; unsigned long reserved;} amdPCNetReceiveDescriptor;typedef struct{ struct { unsigned short mode; unsigned char receiveBufferLength; unsigned char transmitBufferLength; unsigned char physicalAddress[6]; unsigned short reserved; unsigned long filter[2]; unsigned long receiveRingPointer; unsigned long transmitRingPointer; } initBlock; amdPCNetTransmitDescriptor transmitDescriptor[NET_TRANSMIT_BUFFER_NUMBER]; amdPCNetReceiveDescriptor receiveDescriptor[NET_RECEIVE_BUFFER_NUMBER]; unsigned char transmitBuffer[NET_TRANSMIT_BUFFER_NUMBER][NET_TRANSMIT_BUFFER_SIZE]; unsigned char receiveBuffer[NET_RECEIVE_BUFFER_NUMBER][NET_RECEIVE_BUFFER_SIZE]; int currentTransmitBuffer; int currentReceiveBuffer; void * physicalAddress; //physical address of this structure } amdPCNetPrivate;//The PCNet chip can be accessed in two ways: first in word mode, and second in doubleword mode. In DW mode only the lower 2 byte contain data, but we use only word mode, which is mandytorily supported by all devicesstatic inline void amdPCNetReadControlStatusRegister(unsigned long baseIOAddress, int registerIndex, unsigned short * result){ kernelProcessorOutPort16(baseIOAddress + 0x12, registerIndex); kernelProcessorInPort16(baseIOAddress + 0x10, *result);}static inline void amdPCNetWriteControlStatusRegister(unsigned long baseIOAddress, int registerIndex, unsigned short value){ kernelProcessorOutPort16(baseIOAddress + 0x12, registerIndex); kernelProcessorOutPort16(baseIOAddress + 0x10, value);}static void amdPCNetReadBusControlRegister(unsigned long baseIOAddress, int registerIndex, unsigned short * result){ kernelProcessorOutPort16(baseIOAddress + 0x12, registerIndex); kernelProcessorInPort16(baseIOAddress + 0x16, *result);}static inline void amdPCNetWriteBusControlRegister(unsigned long baseIOAddress, int registerIndex, unsigned short value){ kernelProcessorOutPort16(baseIOAddress + 0x12, registerIndex); kernelProcessorOutPort16(baseIOAddress + 0x16, value);}static void amdPCNetReadRegisterAddressPort(unsigned long baseIOAddress, unsigned short * result){ kernelProcessorInPort16(baseIOAddress + 0x12, *result);}static void amdPCNetWriteRegisterAddressPort(unsigned long baseIOAddress, unsigned short value){ kernelProcessorOutPort16(baseIOAddress + 0x12, value);}static inline void amdPCNetReset(unsigned long baseIOAddress) { unsigned short tmp; //first 32bit-reset kernelProcessorOutPort16(baseIOAddress + 0x18, 0x0000); kernelProcessorInPort16(baseIOAddress + 0x18, tmp); //then 16bit-reset so chip is afterwards reset and in 16bit mode kernelProcessorOutPort16(baseIOAddress + 0x14, 0x0000); kernelProcessorInPort16(baseIOAddress + 0x14, tmp);}#if defined(NET_DEBUG)static void debugDumpRegisters(kernelNetworkInterface * nic){ unsigned short tmp; unsigned short tmp2; unsigned short tmp3; //the CSR0 register amdPCNetReadControlStatusRegister(nic->portIOAddress, 0, &tmp); kernelLog("%s->CSR0: %04x", nic->name, tmp); //the CSR3 register amdPCNetReadControlStatusRegister(nic->portIOAddress, 3, &tmp); kernelLog("%s->CSR3: %04x", nic->name, tmp); //the CSR4 register amdPCNetReadControlStatusRegister(nic->portIOAddress, 4, &tmp); kernelLog("%s->CSR4: %04x", nic->name, tmp); //the CSR5 register amdPCNetReadControlStatusRegister(nic->portIOAddress, 5, &tmp); kernelLog("%s->CSR5: %04x", nic->name, tmp); //the CSR6 register amdPCNetReadControlStatusRegister(nic->portIOAddress, 6, &tmp); kernelLog("%s->CSR6: %04x", nic->name, tmp); //the CSR6 register //tell chip to stop first or we cannot read address amdPCNetReadControlStatusRegister(nic->portIOAddress, 0, &tmp); amdPCNetWriteControlStatusRegister(nic->portIOAddress, 0, tmp | CSR0_STOP); amdPCNetReadControlStatusRegister(nic->portIOAddress, 12, &tmp); amdPCNetReadControlStatusRegister(nic->portIOAddress, 13, &tmp2); amdPCNetReadControlStatusRegister(nic->portIOAddress, 14, &tmp3); kernelLog("%s->physicalAddress: %02x:%02x:%02x:%02x:%02x:%02x", nic->name, tmp & 0xff, tmp >> 8, tmp2 & 0xff, tmp2 >> 8, tmp3 & 0xff, tmp3 >> 8); amdPCNetReadControlStatusRegister(nic->portIOAddress, 0, &tmp); amdPCNetWriteControlStatusRegister(nic->portIOAddress, 0, tmp | CSR0_START); }#endif/** * Initializes the chip with its basic data. * Sets up mode, etc and gives the NIC an init block from which it reads the configuration values. */ static void amdPCNetInitChip(kernelNetworkInterface * nic){ amdPCNetPrivate * privateVirtual = (amdPCNetPrivate *) nic->privateData; amdPCNetPrivate * privatePhysical = (amdPCNetPrivate *) privateVirtual->physicalAddress; unsigned short tmp; int i; //Setup the init block// privateVirtual->initBlock.mode = 0x0000;// privateVirtual->initBlock.receiveBufferLength = 2; //real length = 2^2 = 4// privateVirtual->initBlock.transmitBufferLength = 2; //real length = 2^2 = 4 /* privateVirtual->initBlock.physicalAddress[0] = 0x09; privateVirtual->initBlock.physicalAddress[1] = 0x18; privateVirtual->initBlock.physicalAddress[2] = 0x27; privateVirtual->initBlock.physicalAddress[3] = 0x36; privateVirtual->initBlock.physicalAddress[4] = 0x45; privateVirtual->initBlock.physicalAddress[5] = 0x54; i = 0;*//* for(i = 0; i< 6; i++) privateVirtual->initBlock.physicalAddress[i] = nic->myAddress[i]; privateVirtual->initBlock.reserved = 0x0000; privateVirtual->initBlock.filter[0] = 0x00000000; privateVirtual->initBlock.filter[1] = 0x00000000; privateVirtual->initBlock.receiveRingPointer = (unsigned long) &privatePhysical->receiveDescriptor[0]; privateVirtual->initBlock.transmitRingPointer = (unsigned long) &privatePhysical->transmitDescriptor[0]; if((unsigned long) &privatePhysical->initBlock.mode & 0x00000003) kernelError(kernel_error, "%s: physical address of init block is not 32bit-aligned", nic->name); */// if(privateVirtual->initBlock.receiveRingPointer & 0x00000003)// kernelError(kernel_error, "%s: physical address of RX descriptor is not 32bit-aligned", nic->name); // if(privateVirtual->initBlock.transmitRingPointer & 0x00000003)// kernelError(kernel_error, "%s: physical address of TX descriptor is not 32bit-aligned", nic->name); //reset the chip amdPCNetReset(nic->portIOAddress); //stop the chip amdPCNetWriteControlStatusRegister(nic->portIOAddress, CONTROLLER_STATUS, CSR0_STOP); //wait a short while to give the chip time to reset kernelProcessorDelay(); //Tell the chip we want 32bit mode (this method is different from the one described in the specs) amdPCNetReadControlStatusRegister(nic->portIOAddress, SOFTWARE_MODE, &tmp); amdPCNetWriteControlStatusRegister(nic->portIOAddress, SOFTWARE_MODE, tmp | CSR58_SOFTWARE_32BIT); //Set some options amdPCNetReadControlStatusRegister(nic->portIOAddress, TEST_FEATURES_CONTROL, &tmp); amdPCNetWriteControlStatusRegister(nic->portIOAddress, TEST_FEATURES_CONTROL, tmp | CSR4_NO_TRANSMIT_INTERRUPT | CSR4_AUTO_PAD_TRANSMIT | CSR4_DISABLE_TX_POLLING | CSR4_DMAPLUS); //Emable burst read and write amdPCNetReadBusControlRegister(nic->portIOAddress, BURST_CONTROL, &tmp); amdPCNetWriteBusControlRegister(nic->portIOAddress, BURST_CONTROL, tmp | BCR18_BURST_READ_ENABLED | BCR18_BURST_WRITE_ENABLED);/* //write address of init block to chip amdPCNetWriteControlStatusRegister(nic->portIOAddress, INIT_BLOCK_ADDRESS_LOW, (unsigned long) &privatePhysical->initBlock & 0xffff); amdPCNetWriteControlStatusRegister(nic->portIOAddress, INIT_BLOCK_ADDRESS_HIGH, ((unsigned long) &privatePhysical->initBlock >> 16) & 0xffff); */ //set mode 0 (default) amdPCNetWriteControlStatusRegister(nic->portIOAddress, MODE, 0x0000); amdPCNetWriteControlStatusRegister(nic->portIOAddress, 76, -NET_RECEIVE_BUFFER_NUMBER & 0xffff); amdPCNetWriteControlStatusRegister(nic->portIOAddress, 78, -NET_TRANSMIT_BUFFER_NUMBER & 0xffff); amdPCNetWriteControlStatusRegister(nic->portIOAddress, 24, (unsigned long) &privatePhysical->receiveDescriptor[0] & 0xffff); amdPCNetWriteControlStatusRegister(nic->portIOAddress, 25, ((unsigned long) &privatePhysical->receiveDescriptor[0] >> 16) & 0xffff); amdPCNetWriteControlStatusRegister(nic->portIOAddress, 30, (unsigned long) &privatePhysical->transmitDescriptor[0] & 0xffff);// amdPCNetWriteControlStatusRegister(nic->portIOAddress, 31, ((unsigned long) &privatePhysical->transmitDescriptor[0] >> 16) & 0xffff); for(i = 0; i < 4; i++) amdPCNetWriteControlStatusRegister(nic->portIOAddress, i + 8, 0x0000); for(i = 0; i < 3; i++) amdPCNetWriteControlStatusRegister(nic->portIOAddress, i + 12, nic->myAddress[i * 2] | (nic->myAddress[i * 2 + 1] << 8));// amdPCNetWriteControlStatusRegister(nic->portIOAddress, 25, ((unsigned long) &privatePhysical->receiveDescriptor[0] >> 16) & 0xffff); //start chip amdPCNetWriteControlStatusRegister(nic->portIOAddress, CONTROLLER_STATUS, CSR0_START | CSR0_INTERRUPT_ENABLE); //Get link status amdPCNetReadBusControlRegister(nic->portIOAddress, LINK_STATUS, (unsigned short *) &nic->linkStatus);#if defined(NET_DEBUG) kernelLog("%s: Link status is %x", nic->name, nic->linkStatus);#endif }/** Function for the NIC driver. Opens the device and initializes all associated data structures. Can be called several times, previously used memory is freed.*/static int kernelNetworkDriverInitialize_AmdPCNet(kernelNetworkInterface * nic){ int status = 0; int i; unsigned short tmp; amdPCNetPrivate * privateVirtual; amdPCNetPrivate * privatePhysical; //Check parameters if(!nic) {#if defined(NET_DEBUG) kernelLog("kernelNetworkDriverInitialize_AmdPCNet: nic == NULL\n");#endif return (status = ERR_NULLPARAMETER); } if(nic->portIOAddress == 0xffffffff) {#if defined(NET_DEBUG) //no valid port address kernelError(kernel_error, "kernelNetworkDriverInitialize_AmdPCNet: Device port is not valid.\n");#endif return (status = ERR_IO); } if(nic->privateData) {#if defined(NET_DEBUG) kernelLog("kernelNetworkDriverInitialize_AmdPCNet: nic->privateData is not NULL. trying to free it.\n");#endif kernelFree(nic->privateData); } if(nic->privateData) {#if defined(NET_DEBUG) kernelLog("kernelNetworkDriverInitialize_AmdPCNet: nic->privateData is not NULL. trying to free it.\n");#endif kernelPageUnmap(KERNELPROCID, nic->privateData, sizeof(amdPCNetPrivate)); kernelFree(nic->privateData); } //reset the NIC's chip amdPCNetReset(nic->portIOAddress); //read the physical adress from PROM for(i = 0; i < 6; i++) kernelProcessorInPort8(nic->portIOAddress + i, nic->myAddress[i]); //Get chip version and name amdPCNetReadControlStatusRegister(nic->portIOAddress, 89, &tmp); nic->version = (unsigned long) tmp << 16; amdPCNetReadControlStatusRegister(nic->portIOAddress, 88, &tmp); nic->version = ((nic->version | tmp) >> 12) & 0xffff; switch(nic->version) { case 0x2420: nic->name = "PCnet/PCI 79C970"; // PCI break; case 0x2621: nic->name = "PCnet/PCI II 79C970A"; // PCI break; case 0x2623: nic->name = "PCnet/FAST 79C971"; // PCI break; case 0x2624: nic->name = "PCnet/FAST+ 79C972"; // PCI break; case 0x2625: nic->name = "PCnet/FAST III 79C973"; // PCI break; case 0x2626: nic->name = "PCnet/Home 79C978"; // PCI break; case 0x2627: nic->name = "PCnet/FAST III 79C975"; // PCI break; case 0x2628: nic->name = "PCnet/PRO 79C976"; break; }#if defined(NET_DEBUG) kernelLog("%s: My address is: %x:%x:%x:%x:%x:%x\n", nic->name, nic->myAddress[0], nic->myAddress[1], nic->myAddress[2], nic->myAddress[3], nic->myAddress[4], nic->myAddress[5]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -