📄 kernelnetworkdriver_amdpcnet.c
字号:
#endif //Allocate physical space for the NIC's private structure privatePhysical = (amdPCNetPrivate *) kernelMemoryGetPhysical(sizeof(amdPCNetPrivate), MEMORY_PAGE_SIZE, "AMD PCNet buffers"); if(!privatePhysical) { kernelError(kernel_error, "kernelNetworkDriverInitialize_AmdPCNet: Can't allocate memory for buffers"); ((kernelNetworkDriver * ) nic->driver)->destroy(nic); return(status = ERR_MEMORY); } //map the physical address from above to a kernel virtual address status = kernelPageMapToFree(KERNELPROCID, privatePhysical, (void **) &privateVirtual, sizeof(amdPCNetPrivate)); if(status < 0) { kernelError(kernel_error, "kernelNetworkDriverInitialize_AmdPCNet: Can't map physical address of buffers to virtual address"); ((kernelNetworkDriver * ) nic->driver)->destroy(nic); return(status); } //Save pointers in the NIC structure privateVirtual->physicalAddress = (void *) privatePhysical; nic->privateData = (void *) privateVirtual; //Clear the memory kernelMemClear(privateVirtual, sizeof(amdPCNetPrivate)); //Hook the card's interrupt BEFORE card can issue any interrupts kernelInterruptHookShared(nic->irq, kernelNetworkDriverHandleInterrupt_AmdPCNet, (void *) nic); //Set up some registers, setup and load init block and start card amdPCNetInitChip(nic); // debugInterruptDo(10); /* //Get and save the MAC address and the broadcast address for(i = 0; i < 3; i++) { amdPCNetReadControlStatusRegister(nic->portIOAddress, i + 0x0c, &tmp); nic->myAddress[i * 2] = (unsigned char) (tmp & 0xff); nic->myAddress[i * 2 + 1] = (unsigned char) ((tmp >> 8) & 0xff); nic->broadcastAddress[i * 2] = 0xff; nic->broadcastAddress[i * 2 + 1] = 0xff; } kernelLog("My MAC address: %x:%x:%x:%x:%x:%x\n", nic->myAddress[0], nic->myAddress[1], nic->myAddress[2], nic->myAddress[3], nic->myAddress[4], nic->myAddress[5]); //Get chip version amdPCNetReadControlStatusRegister(nic->portIOAddress, 89, &tmp); chipVersion = (unsigned long) tmp << 16; amdPCNetReadControlStatusRegister(nic->portIOAddress, 88, &tmp); chipVersion |= tmp; chipVersion = (chipVersion >> 12) & 0xffff; switch(chipVersion) { case 0x2420: chipName = "PCnet/PCI 79C970"; // PCI break; case 0x2430: chipName = "PCnet/32 79C965"; // 486/VL bus break; case 0x2621: chipName = "PCnet/PCI II 79C970A"; // PCI break; case 0x2623: chipName = "PCnet/FAST 79C971"; // PCI break; case 0x2624: chipName = "PCnet/FAST+ 79C972"; // PCI break; case 0x2625: chipName = "PCnet/FAST III 79C973"; // PCI break; case 0x2626: chipName = "PCnet/Home 79C978"; // PCI break; case 0x2627: chipName = "PCnet/FAST III 79C975"; // PCI break; case 0x2628: chipName = "PCnet/PRO 79C976"; break; } //TODO: Register interrupt if((chipVersion != 0x2420 && chipVersion < 0x2621 && chipVersion > 0x2628) || chipVersion == 0x2622) { //unsupported chip //free resources and exit#if defined(NET_DEBUG) kernelLog("Chip version \"%s\" of the AMD PCNet32 NIC is not supported!\n", chipName);#endif ((kernelNetworkDriver * ) nic->driver)->destroy(nic); return(status = ERR_INVALID); } #if defined(NET_DEBUG) kernelLog("Chip Name %s recognized (ID: %x)\n", chipName, chipVersion); #endif //Save the name of this network device //TODO: What if there are two identical NICs in a computer? nic->name = chipName; //reset the chip again amdPCNetReset(nic->portIOAddress); //Clear logical address filter (since we want to receive packets from all MAC addresses) for(i = 0; i < 4; i++) { amdPCNetWriteControlStatusRegister(nic->portIOAddress, i + 8, 0x0000); } //program number of descriptors in transmit ring //number to be set is the two's complement of the real number amdPCNetWriteControlStatusRegister(nic->portIOAddress, 78, -NET_TRANSMIT_BUFFER_NUMBER); //program number of descriptors in receive ring amdPCNetWriteControlStatusRegister(nic->portIOAddress, 76, -NET_RECEIVE_BUFFER_NUMBER); //allocate space for the device private structure //(the transmit and receive ring structures, the transmit and the receive buffer) //memory must be 32bit-aligned //TODO: Memory allocation is suboptimal since whole block is used. What to do? privatePhysicalAddress = (amdPCNetPrivate *) kernelMemoryGetPhysical(sizeof(amdPCNetPrivate), MEMORY_PAGE_SIZE, "AMD PCNet buffers"); if(!privatePhysicalAddress) {#if defined(NET_DEBUG) kernelLog("Can't allocate memory for buffers\n");#endif ((kernelNetworkDriver * ) nic->driver)->destroy(nic); return(status = ERR_MEMORY); } //map the physical address from above to a kernel virtual address status = kernelPageMapToFree(KERNELPROCID, privatePhysicalAddress, (void **) &nic->privateData, sizeof(amdPCNetPrivate)); if(status < 0) {#if defined(NET_DEBUG) kernelLog("Can't map physical address of transmit buffer to virtual address\n");#endif ((kernelNetworkDriver * ) nic->driver)->destroy(nic); return(status); } //save the physical address of the NIC's private structure ((amdPCNetPrivate *) nic->privateData)->thisStructurePhysicalAddress = (void *) privatePhysicalAddress; //clear the NIC's private structure kernelMemClear(nic->privateData, sizeof(amdPCNetPrivate)); //Setup the init block used to intialize the NIC //Save pointers to transmit/receive ring into init block ((amdPCNetPrivate *) nic->privateData)->initBlock.receiveRingPointer = (unsigned long) &privatePhysicalAddress->receiveDescriptor[0]; ((amdPCNetPrivate *) nic->privateData)->initBlock.transmitRingPointer = (unsigned long) &privatePhysicalAddress->transmitDescriptor[0]; //disable transmit and receive ((amdPCNetPrivate *) nic->privateData)->initBlock.mode = 0x0003; //set receive and transmit ring size ((amdPCNetPrivate *) nic->privateData)->initBlock.receiveBufferLength_transmitBufferLength = TX_RING_LEN_BITS | RX_RING_LEN_BITS; //set physical address for (i = 0; i < 6; i++) ((amdPCNetPrivate *) nic->privateData)->initBlock.physicalAddress[i] = nic->myAddress[i]; //Clear filters ((amdPCNetPrivate *) nic->privateData)->initBlock.filter[0] = 0x00000000; ((amdPCNetPrivate *) nic->privateData)->initBlock.filter[1] = 0x00000000; //Switch the NIC to 32 bit mode amdPCNetWriteBaseControlRegister(nic->portIOAddress, 20, 2); //give the NIC the address of the initialisation block amdPCNetWriteBaseControlRegister(nic->portIOAddress, 1, (unsigned short) ((unsigned long) &privatePhysicalAddress->initBlock &0xffff)); amdPCNetWriteBaseControlRegister(nic->portIOAddress, 2, (unsigned short) ((unsigned long) &privatePhysicalAddress->initBlock >> 16)); //Clear both logical address filters for(i = 0; i < 4; i++) amdPCNetWriteControlStatusRegister(nic->portIOAddress, i + 8, 0x0000); //store length of receive ring (value is the negative of the real length) amdPCNetWriteControlStatusRegister(nic->portIOAddress, 76, -RX_RING_SIZE); //store length of transmit ring (value is the negative of the real length) amdPCNetWriteControlStatusRegister(nic->portIOAddress, 78, -TX_RING_SIZE); //store physical address of first transmit descriptor in the NIC's registers amdPCNetWriteControlStatusRegister(nic->portIOAddress, 31, (unsigned short) ((unsigned long) &privatePhysicalAddress->transmitDescriptor[0] & 0xffff)); amdPCNetWriteControlStatusRegister(nic->portIOAddress, 31, (unsigned short) ((unsigned long) &privatePhysicalAddress->transmitDescriptor[0] >> 16)); //store physical address of first receive descriptor in the NIC's registers amdPCNetWriteControlStatusRegister(nic->portIOAddress, 25, (unsigned short) ((unsigned long) &privatePhysicalAddress->receiveDescriptor[0] & 0xffff)); amdPCNetWriteControlStatusRegister(nic->portIOAddress, 25, (unsigned short) ((unsigned long) &privatePhysicalAddress->receiveDescriptor[0] >> 16)); //Set default values in the mode register amdPCNetWriteControlStatusRegister(nic->portIOAddress, 15, 0x0000); //enable the card's leds amdPCNetWriteBusControlRegister(nic->portIOAddress, 2, 0x1002); //Hook the card's interrupt kernelInterruptHookShared(nic->irq, kernelNetworkDriverHandleInterrupt_AmdPCNet, (void *) nic); //start the *** thing// amdPCNetWriteControlStatusRegister(nic->portIOAddress, 4, 0x9150); amdPCNetWriteControlStatusRegister(nic->portIOAddress, 0, 0x0042); amdPCNetReadControlStatusRegister(nic->portIOAddress, 0, &tmp); kernelError(kernel_error, "CSR0: %x", tmp); */ /* //wait until it is initialized for(i = 0; i < 100; i++) { amdPCNetReadControlStatusRegister(nic->portIOAddress, 0, &tmp); if(tmp & 0x0100) break; } kernelError(kernel_error, "device has private struct at %x", privatePhysicalAddress); amdPCNetWriteControlStatusRegister(nic->portIOAddress, 0, 0x0042);*/ return (status = 0);}/***************************************************************************************************************//** * Releases all memory associated with the network device. * Frees the pci information structure nic->busData, the NIC's private structure nic->privateData, * and at last the NIC's structure intself (nic). Unhooks the cards interrupt before it does so. * NOTE: If you just want to reinitialize the pcnet, call kernelNetworkDriverInitialize again, it will * free memory previously used. */static int kernelNetworkDriverDestroy_AmdPCNet(kernelNetworkInterface * nic){ int status; void * privatePhysical = NULL; //TODO: unregister interrupt //get physical address of the private structure if(!nic || !nic->privateData) privatePhysical = ((amdPCNetPrivate *) nic->privateData)->physicalAddress; //disable the device (routine just returns errorcode if nic->busData is NULL) if(!nic) kernelBusPCIDisable((kernelBusPCIDevice *) (nic->busData)); //free memory used by bus data structure (p. ex. kernelBusPCIDevice) if(!nic || !nic->busData) kernelFree(nic->busData); //free memory used by device private structure if(!nic || !nic->privateData) kernelPageUnmap(KERNELPROCID, nic->privateData, sizeof(amdPCNetPrivate)); //release physical memory used by private structure if(!privatePhysical) kernelMemoryReleasePhysical(privatePhysical); //free memory used by driver structure if(!nic || !nic->driver) kernelFree(nic->driver); //free memory used by NIC structure if(!nic) kernelFree((void *) nic); return (status = 0);}/***************************************************************************************************************/static int kernelNetworkDriverHandleInterrupt_AmdPCNet(void * data){ int status; kernelNetworkInterface * nic = (kernelNetworkInterface *) data; unsigned short oldRapValue; //the value of the RegisterAddressPort before we modify it unsigned short tmp; kernelError(kernel_error, "Jippee! %s is handling an Interrupt!", nic->name); //read value of register address port amdPCNetReadRegisterAddressPort(nic->portIOAddress, &oldRapValue); amdPCNetReadControlStatusRegister(nic->portIOAddress, CONTROLLER_STATUS, &tmp); if(!(tmp & CSR0_INTERRUPT_OCCURED)) { //this device did not cause the interrupt //restore RAP and exit amdPCNetWriteRegisterAddressPort(nic->portIOAddress, oldRapValue); return (status = -1); } //disable interrupts amdPCNetWriteControlStatusRegister(nic->portIOAddress, CONTROLLER_STATUS, 0); debugDumpRegisters(nic); //Restore RAP amdPCNetWriteRegisterAddressPort(nic->portIOAddress, oldRapValue); return (status = 0);}/***************************************************************************************************************/static int kernelNetworkDriverTransmit_AmdPCNet(kernelNetworkInterface * nic, void * data, int length){ int status; amdPCNetPrivate * privateVirtual = (amdPCNetPrivate *) nic->privateData; amdPCNetPrivate * privatePhysical = (amdPCNetPrivate *) privateVirtual->physicalAddress; debugDumpRegisters(nic); if(length >= NET_TRANSMIT_BUFFER_SIZE) {#if defined(NET_DEBUG) kernelLog("%s: Packet length %u is too long. Max packet length is %u\n", nic->name, length, NET_TRANSMIT_BUFFER_SIZE);#endif return (status = ERR_BOUNDS); } if((*privateVirtual).transmitDescriptor[privateVirtual->currentTransmitBuffer].statusBits & 0x8000) {#if defined(NET_DEBUG) kernelLog("%s: still sending packet in slot %u\n", nic->name, privateVirtual->currentTransmitBuffer);#endif return (status = ERR_BUSY);// while((*privateData).transmitDescriptor[privateData->currentTransmitBuffer].statusBits & 0x8000); }#if defined(NET_DEBUG) kernelLog("%s: sending packet of length %u in slot %u", nic->name, length, privateVirtual->currentTransmitBuffer);#endif //get the lock on the NIC kernelLockGet(&nic->interfaceLock); //copy the data to the dma accessible memory kernelMemCopy(data, (void *) &privateVirtual->transmitBuffer[privateVirtual->currentTransmitBuffer], length); //Set the buffer base address in the descriptor (*privateVirtual).transmitDescriptor[privateVirtual->currentTransmitBuffer].bufferBaseAddress = (unsigned long) &privatePhysical->transmitBuffer[privateVirtual->currentTransmitBuffer]; //set the negative message length in the descriptor (*privateVirtual).transmitDescriptor[privateVirtual->currentTransmitBuffer].bufferLength = 0xf000 | -length; //set the own bit, so the NIC owns this descriptor now (*privateVirtual).transmitDescriptor[privateVirtual->currentTransmitBuffer].statusBits = TD_START_OF_PACKET | TD_END_OF_PACKET | TD_OWNED_BY_NIC; //Tell the NIC to send the packet amdPCNetWriteControlStatusRegister(nic->portIOAddress, CONTROLLER_STATUS, CSR0_INTERRUPT_ENABLE | CSR0_TRANSMIT_DEMAND); //use next transmit buffer next time privateVirtual->currentTransmitBuffer = (privateVirtual->currentTransmitBuffer + 1) % NET_TRANSMIT_BUFFER_NUMBER; //free lock kernelLockRelease(&nic->interfaceLock); return (status = 0);}/******************************************************************************/// FUNCTION EXPORTED FOR EXTERNAL USE ///******************************************************************************/void kernelNetworkGetDriver_AmdPCNet(kernelNetworkInterface * nic){ kernelNetworkDriver * driver = (kernelNetworkDriver *) kernelMalloc(sizeof(kernelNetworkDriver)); nic->addressLength = ETHERNET_ADDRESS_LENGTH; //netDriver->myAddress must be initialized by driver nic->headerPreambleLength = ETHERNET_PREAMBLE_LENGTH; driver->initialize = kernelNetworkDriverInitialize_AmdPCNet; driver->destroy = kernelNetworkDriverDestroy_AmdPCNet; driver->transmit = kernelNetworkDriverTransmit_AmdPCNet; nic->driver = (void *) driver; nic->privateData = (void *) 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -