diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/ndis/sonic/request.c | 890 |
1 files changed, 890 insertions, 0 deletions
diff --git a/private/ntos/ndis/sonic/request.c b/private/ntos/ndis/sonic/request.c new file mode 100644 index 000000000..d17d67791 --- /dev/null +++ b/private/ntos/ndis/sonic/request.c @@ -0,0 +1,890 @@ +/*++ + +Copyright (c) 1990-1992 Microsoft Corporation + +Module Name: + + request.c + +Abstract: + + This is the cose to handle requests for the National Semiconductor + SONIC Ethernet controller. This driver conforms to the NDIS 3.0 + miniport interface. + +Author: + + Adam Barr (adamba) 14-Nov-1990 + +Environment: + + Kernel Mode - Or whatever is the equivalent. + +Revision History: + + +--*/ + +#include <ndis.h> + +#include <sonichrd.h> +#include <sonicsft.h> + + + +// +// This macro determines if the directed address +// filtering in the CAM is actually necessary given +// the current filter. +// + +#define CAM_DIRECTED_SIGNIFICANT(_Filter) \ + ((((_Filter) & NDIS_PACKET_TYPE_DIRECTED) && \ + (!((_Filter) & NDIS_PACKET_TYPE_PROMISCUOUS))) ? 1 : 0) + + +// +// This macro determines if the multicast filtering in +// the CAM are actually necessary given the current filter. +// + +#define CAM_MULTICAST_SIGNIFICANT(_Filter) \ + ((((_Filter) & NDIS_PACKET_TYPE_MULTICAST) && \ + (!((_Filter) & (NDIS_PACKET_TYPE_ALL_MULTICAST | \ + NDIS_PACKET_TYPE_PROMISCUOUS)))) ? 1 : 0) + + +STATIC +NDIS_STATUS +ChangeClassDispatch( + IN PSONIC_ADAPTER Adapter, + IN UINT NewFilterClasses + ); + +STATIC +NDIS_STATUS +ChangeAddressDispatch( + IN PSONIC_ADAPTER Adapter, + IN UINT AddressCount, + IN CHAR Addresses[][ETH_LENGTH_OF_ADDRESS] + ); + + + + +extern +NDIS_STATUS +SonicQueryInformation( + IN NDIS_HANDLE MiniportAdapterContext, + IN NDIS_OID Oid, + IN PVOID InformationBuffer, + IN ULONG InformationBufferLength, + OUT PULONG BytesWritten, + OUT PULONG BytesNeeded + ) + +/*++ + +Routine Description: + + SonicQueryInformation handles a query operation for a + single OID. + +Arguments: + + MiniportAdapterContext - Context registered with the wrapper, really + a pointer to the adapter. + + Oid - The OID of the query. + + InformationBuffer - Holds the result of the query. + + InformationBufferLength - The length of InformationBuffer. + + BytesWritten - If the call is successful, returns the number + of bytes written to InformationBuffer. + + BytesNeeded - If there is not enough room in InformationBuffer + to satisfy the OID, returns the amount of storage needed. + +Return Value: + + NDIS_STATUS_SUCCESS + NDIS_STATUS_PENDING + NDIS_STATUS_INVALID_LENGTH + NDIS_STATUS_INVALID_OID + +--*/ + +{ + PSONIC_ADAPTER Adapter = PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); + INT i; + INT SupportedOids; + NDIS_OID MaskOid; + PVOID SourceBuffer; + ULONG SourceBufferLength; + ULONG GenericUlong; + USHORT GenericUshort; + UCHAR VendorId[4]; +#ifdef SONIC_EISA + static const UCHAR EisaDescriptor[] = "SONIC EISA Bus Master Ethernet Adapter (DP83932EB-EISA)"; +#endif +#ifdef SONIC_INTERNAL + static const UCHAR InternalDescriptor[] = "MIPS R4000 on-board network controller"; +#endif + + static const NDIS_OID SonicSupportedOids[] = { + OID_GEN_SUPPORTED_LIST, + OID_GEN_HARDWARE_STATUS, + OID_GEN_MEDIA_SUPPORTED, + OID_GEN_MEDIA_IN_USE, + OID_GEN_MAXIMUM_LOOKAHEAD, + OID_GEN_MAXIMUM_FRAME_SIZE, + OID_GEN_MAXIMUM_TOTAL_SIZE, + OID_GEN_MAC_OPTIONS, + OID_GEN_PROTOCOL_OPTIONS, + OID_GEN_LINK_SPEED, + OID_GEN_TRANSMIT_BUFFER_SPACE, + OID_GEN_RECEIVE_BUFFER_SPACE, + OID_GEN_TRANSMIT_BLOCK_SIZE, + OID_GEN_RECEIVE_BLOCK_SIZE, + OID_GEN_VENDOR_ID, + OID_GEN_VENDOR_DESCRIPTION, + OID_GEN_DRIVER_VERSION, + OID_GEN_CURRENT_PACKET_FILTER, + OID_GEN_CURRENT_LOOKAHEAD, + OID_GEN_XMIT_OK, + OID_GEN_RCV_OK, + OID_GEN_XMIT_ERROR, + OID_GEN_RCV_ERROR, + OID_GEN_RCV_NO_BUFFER, + OID_GEN_DIRECTED_BYTES_XMIT, + OID_GEN_DIRECTED_FRAMES_XMIT, + OID_GEN_MULTICAST_BYTES_XMIT, + OID_GEN_MULTICAST_FRAMES_XMIT, + OID_GEN_BROADCAST_BYTES_XMIT, + OID_GEN_BROADCAST_FRAMES_XMIT, + OID_GEN_DIRECTED_BYTES_RCV, + OID_GEN_DIRECTED_FRAMES_RCV, + OID_GEN_MULTICAST_BYTES_RCV, + OID_GEN_MULTICAST_FRAMES_RCV, + OID_GEN_BROADCAST_BYTES_RCV, + OID_GEN_BROADCAST_FRAMES_RCV, + OID_GEN_RCV_CRC_ERROR, + OID_GEN_TRANSMIT_QUEUE_LENGTH, + OID_802_3_PERMANENT_ADDRESS, + OID_802_3_CURRENT_ADDRESS, + OID_802_3_MULTICAST_LIST, + OID_802_3_MAXIMUM_LIST_SIZE, + OID_802_3_RCV_ERROR_ALIGNMENT, + OID_802_3_XMIT_ONE_COLLISION, + OID_802_3_XMIT_MORE_COLLISIONS, + OID_802_3_XMIT_DEFERRED, + OID_802_3_XMIT_MAX_COLLISIONS, + OID_802_3_RCV_OVERRUN, + OID_802_3_XMIT_UNDERRUN, + OID_802_3_XMIT_HEARTBEAT_FAILURE, + OID_802_3_XMIT_TIMES_CRS_LOST, + OID_802_3_XMIT_LATE_COLLISIONS + }; + + // + // Check that the OID is valid. + // + + SupportedOids = sizeof(SonicSupportedOids)/sizeof(ULONG); + + for (i=0; i<SupportedOids; i++) { + if (Oid == SonicSupportedOids[i]) { + break; + } + } + + if (i == SupportedOids) { + *BytesWritten = 0; + return NDIS_STATUS_INVALID_OID; + } + + // + // Initialize these once, since this is the majority + // of cases. + // + + SourceBuffer = &GenericUlong; + SourceBufferLength = sizeof(ULONG); + + switch (Oid & OID_TYPE_MASK) { + + case OID_TYPE_GENERAL_OPERATIONAL: + + switch (Oid) { + + case OID_GEN_MAC_OPTIONS: + + GenericUlong = (ULONG)(NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | + NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | + NDIS_MAC_OPTION_RECEIVE_SERIALIZED | + NDIS_MAC_OPTION_NO_LOOPBACK + ); + + break; + + case OID_GEN_SUPPORTED_LIST: + + SourceBuffer = (PVOID)SonicSupportedOids; + SourceBufferLength = SupportedOids * sizeof(ULONG); + break; + + case OID_GEN_HARDWARE_STATUS: + + GenericUlong = NdisHardwareStatusReady; + break; + + case OID_GEN_MEDIA_SUPPORTED: + + GenericUlong = NdisMedium802_3; + break; + + case OID_GEN_MEDIA_IN_USE: + + GenericUlong = NdisMedium802_3; + break; + + case OID_GEN_MAXIMUM_LOOKAHEAD: + + GenericUlong = (SONIC_INDICATE_MAXIMUM-14 < SONIC_LOOPBACK_MAXIMUM) ? + SONIC_INDICATE_MAXIMUM-14 : SONIC_LOOPBACK_MAXIMUM; + break; + + case OID_GEN_MAXIMUM_FRAME_SIZE: + + GenericUlong = 1500; + break; + + case OID_GEN_MAXIMUM_TOTAL_SIZE: + + GenericUlong = 1514; + break; + + case OID_GEN_LINK_SPEED: + + GenericUlong = 100000; // 10 Mbps in 100 bps units + break; + + case OID_GEN_TRANSMIT_BUFFER_SPACE: + + GenericUlong = SONIC_LARGE_BUFFER_SIZE * SONIC_NUMBER_OF_TRANSMIT_DESCRIPTORS; + break; + + case OID_GEN_RECEIVE_BUFFER_SPACE: + + GenericUlong = SONIC_LARGE_BUFFER_SIZE * SONIC_NUMBER_OF_RECEIVE_DESCRIPTORS; + break; + + case OID_GEN_TRANSMIT_BLOCK_SIZE: + + GenericUlong = SONIC_LARGE_BUFFER_SIZE; + break; + + case OID_GEN_RECEIVE_BLOCK_SIZE: + + GenericUlong = SONIC_LARGE_BUFFER_SIZE; + break; + + case OID_GEN_VENDOR_ID: + + SONIC_MOVE_MEMORY(VendorId, Adapter->PermanentNetworkAddress, 3); + VendorId[3] = 0x0; + SourceBuffer = VendorId; + SourceBufferLength = sizeof(VendorId); + break; + + case OID_GEN_VENDOR_DESCRIPTION: + + switch (Adapter->AdapterType) { +#ifdef SONIC_EISA + case SONIC_ADAPTER_TYPE_EISA: + SourceBuffer = (PVOID)EisaDescriptor; + SourceBufferLength = sizeof(EisaDescriptor); + break; +#endif +#ifdef SONIC_INTERNAL + case SONIC_ADAPTER_TYPE_INTERNAL: + SourceBuffer = (PVOID)InternalDescriptor; + SourceBufferLength = sizeof(InternalDescriptor); + break; +#endif + default: + ASSERT(FALSE); + break; + } + break; + + case OID_GEN_DRIVER_VERSION: + + GenericUshort = (SONIC_NDIS_MAJOR_VERSION << 8) + SONIC_NDIS_MINOR_VERSION; + SourceBuffer = &GenericUshort; + SourceBufferLength = sizeof(USHORT); + break; + + case OID_GEN_CURRENT_PACKET_FILTER: + + GenericUlong = Adapter->CurrentPacketFilter; + break; + + case OID_GEN_CURRENT_LOOKAHEAD: + + GenericUlong = (SONIC_INDICATE_MAXIMUM-14 < SONIC_LOOPBACK_MAXIMUM) ? + SONIC_INDICATE_MAXIMUM-14 : SONIC_LOOPBACK_MAXIMUM; + break; + + default: + + ASSERT(FALSE); + break; + + } + + break; + + case OID_TYPE_GENERAL_STATISTICS: + + MaskOid = (Oid & OID_INDEX_MASK) - 1; + + switch (Oid & OID_REQUIRED_MASK) { + + case OID_REQUIRED_MANDATORY: + + ASSERT (MaskOid < GM_ARRAY_SIZE); + + if (MaskOid == GM_RECEIVE_NO_BUFFER) { + + // + // This one is read off the card, update unless our + // counter is more (which indicates an imminent + // overflow interrupt, so we don't update). + // + + USHORT MissedPacket; + SONIC_READ_PORT(Adapter, SONIC_FRAME_ALIGNMENT_ERROR, &MissedPacket); + + if ((Adapter->GeneralMandatory[GM_RECEIVE_NO_BUFFER] & 0xffff) < + MissedPacket) { + + Adapter->GeneralMandatory[GM_RECEIVE_NO_BUFFER] = + (Adapter->GeneralMandatory[GM_RECEIVE_NO_BUFFER] & 0xffff0000) + + MissedPacket; + + } + } + + GenericUlong = Adapter->GeneralMandatory[MaskOid]; + break; + + case OID_REQUIRED_OPTIONAL: + + ASSERT (MaskOid < GO_ARRAY_SIZE); + + if (MaskOid == GO_RECEIVE_CRC) { + + // + // This one is read off the card, update unless our + // counter is more (which indicates an imminent + // overflow interrupt, so we don't update). + // + + USHORT CrcError; + SONIC_READ_PORT(Adapter, SONIC_FRAME_ALIGNMENT_ERROR, &CrcError); + + if ((Adapter->GeneralOptional[GO_RECEIVE_CRC - GO_ARRAY_START] & 0xffff) < + CrcError) { + + Adapter->GeneralOptional[GO_RECEIVE_CRC - GO_ARRAY_START] = + (Adapter->GeneralOptional[GO_RECEIVE_CRC - GO_ARRAY_START] & 0xffff0000) + + CrcError; + + } + } + + if ((MaskOid / 2) < GO_COUNT_ARRAY_SIZE) { + + if (MaskOid & 0x01) { + // Frame count + GenericUlong = Adapter->GeneralOptionalFrameCount[MaskOid / 2]; + } else { + // Byte count + SourceBuffer = &Adapter->GeneralOptionalByteCount[MaskOid / 2]; + SourceBufferLength = sizeof(LARGE_INTEGER); + } + + } else { + + GenericUlong = Adapter->GeneralOptional[MaskOid - GO_ARRAY_START]; + + } + + break; + + default: + + ASSERT(FALSE); + break; + + } + + break; + + case OID_TYPE_802_3_OPERATIONAL: + + switch (Oid) { + + case OID_802_3_PERMANENT_ADDRESS: + + SourceBuffer = Adapter->PermanentNetworkAddress; + SourceBufferLength = 6; + break; + + case OID_802_3_CURRENT_ADDRESS: + + SourceBuffer = Adapter->CurrentNetworkAddress; + SourceBufferLength = 6; + break; + + case OID_802_3_MAXIMUM_LIST_SIZE: + + GenericUlong = SONIC_CAM_ENTRIES - 1; + break; + + default: + + ASSERT(FALSE); + break; + + } + + break; + + case OID_TYPE_802_3_STATISTICS: + + MaskOid = (Oid & OID_INDEX_MASK) - 1; + + switch (Oid & OID_REQUIRED_MASK) { + + case OID_REQUIRED_MANDATORY: + + ASSERT (MaskOid < MM_ARRAY_SIZE); + + if (MaskOid == MM_RECEIVE_ERROR_ALIGNMENT) { + + // + // This one is read off the card, update unless our + // counter is more (which indicates an imminent + // overflow interrupt, so we don't update). + // + + USHORT FaError; + SONIC_READ_PORT(Adapter, SONIC_FRAME_ALIGNMENT_ERROR, &FaError); + + if ((Adapter->MediaMandatory[MM_RECEIVE_ERROR_ALIGNMENT] & 0xffff) < + FaError) { + + Adapter->MediaMandatory[MM_RECEIVE_ERROR_ALIGNMENT] = + (Adapter->MediaMandatory[MM_RECEIVE_ERROR_ALIGNMENT] & 0xffff0000) + + FaError; + + } + } + + GenericUlong = Adapter->MediaMandatory[MaskOid]; + break; + + case OID_REQUIRED_OPTIONAL: + + ASSERT (MaskOid < MO_ARRAY_SIZE); + GenericUlong = Adapter->MediaOptional[MaskOid]; + break; + + default: + + ASSERT(FALSE); + break; + + } + + break; + + } + + if (SourceBufferLength > InformationBufferLength) { + *BytesNeeded = SourceBufferLength; + return NDIS_STATUS_INVALID_LENGTH; + } + + SONIC_MOVE_MEMORY (InformationBuffer, SourceBuffer, SourceBufferLength); + *BytesWritten = SourceBufferLength; + + return NDIS_STATUS_SUCCESS; + +} + + +STATIC +NDIS_STATUS +SonicSetInformation( + IN NDIS_HANDLE MiniportAdapterContext, + IN NDIS_OID Oid, + IN PVOID InformationBuffer, + IN ULONG InformationBufferLength, + OUT PULONG BytesRead, + OUT PULONG BytesNeeded + ) + +/*++ + +Routine Description: + + SonicQueryInformation handles a set operation for a + single OID. + +Arguments: + + MiniportAdapterContext - Context registered with the wrapper, really + a pointer to the adapter. + + Oid - The OID of the set. + + InformationBuffer - Holds the data to be set. + + InformationBufferLength - The length of InformationBuffer. + + BytesRead - If the call is successful, returns the number + of bytes read from InformationBuffer. + + BytesNeeded - If there is not enough data in InformationBuffer + to satisfy the OID, returns the amount of storage needed. + +Return Value: + + NDIS_STATUS_SUCCESS + NDIS_STATUS_PENDING + NDIS_STATUS_INVALID_LENGTH + NDIS_STATUS_INVALID_OID + +--*/ + +{ + + PSONIC_ADAPTER Adapter = PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); + NDIS_STATUS Status; + ULONG PacketFilter; + + // + // Now check for the most common OIDs + // + + switch (Oid) { + + case OID_802_3_MULTICAST_LIST: + + if (InformationBufferLength % ETH_LENGTH_OF_ADDRESS != 0) { + + // + // The data must be a multiple of the Ethernet + // address size. + // + + return NDIS_STATUS_INVALID_DATA; + + } +#if DBG + if (SonicDbg) { + DbgPrint("Processing Change Multicast List request\n"); + } +#endif + + // + // Now make the change. + // + + Status = ChangeAddressDispatch( + Adapter, + InformationBufferLength / ETH_LENGTH_OF_ADDRESS, + InformationBuffer + ); + + *BytesRead = InformationBufferLength; + + return Status; + + break; + + case OID_GEN_CURRENT_PACKET_FILTER: + + if (InformationBufferLength != 4) { + + *BytesNeeded = 4; + return NDIS_STATUS_INVALID_LENGTH; + + } + +#if DBG + if (SonicDbg) { + DbgPrint("Processing Change Packet Filter request\n"); + } +#endif + + // + // Now call the filter package to set the packet filter. + // + + SONIC_MOVE_MEMORY ((PVOID)&PacketFilter, InformationBuffer, sizeof(ULONG)); + + // + // Verify bits + // + + if (PacketFilter & (NDIS_PACKET_TYPE_SOURCE_ROUTING | + NDIS_PACKET_TYPE_SMT | + NDIS_PACKET_TYPE_MAC_FRAME | + NDIS_PACKET_TYPE_FUNCTIONAL | + NDIS_PACKET_TYPE_ALL_FUNCTIONAL | + NDIS_PACKET_TYPE_GROUP + )) { + + *BytesRead = 4; + *BytesNeeded = 0; + + return NDIS_STATUS_NOT_SUPPORTED; + + } + + Status = ChangeClassDispatch( + Adapter, + PacketFilter + ); + + *BytesRead = 4; + return Status; + + break; + + case OID_GEN_CURRENT_LOOKAHEAD: + + // + // No need to record requested lookahead length since we + // always indicate the whole packet. + // + + *BytesRead = 4; + return NDIS_STATUS_SUCCESS; + break; + + default: + + return NDIS_STATUS_INVALID_OID; + break; + + } + +} + +STATIC +NDIS_STATUS +ChangeClassDispatch( + IN PSONIC_ADAPTER Adapter, + IN UINT NewFilterClasses + ) + +/*++ + +Routine Description: + + Modifies the Receive Control Register and Cam Enable registers, + then re-loads the CAM if necessary. + +Arguments: + + Adapter - The adapter. + + NewFilterClasses - New set of filters. + +Return Value: + + NDIS_STATUS_PENDING - if the CAM was reloaded. + NDIS_STATUS_SUCCESS - otherwise. + +--*/ + +{ + // + // The new value for the RCR. + // + USHORT NewReceiveControl = SONIC_RCR_DEFAULT_VALUE; + + // + // First take care of the Receive Control Register. + // + + if (NewFilterClasses & NDIS_PACKET_TYPE_PROMISCUOUS) { + + NewReceiveControl |= SONIC_RCR_PROMISCUOUS_PHYSICAL | + SONIC_RCR_ACCEPT_BROADCAST | + SONIC_RCR_ACCEPT_ALL_MULTICAST; + + } else { + + if (NewFilterClasses & NDIS_PACKET_TYPE_ALL_MULTICAST) { + + NewReceiveControl |= SONIC_RCR_ACCEPT_ALL_MULTICAST; + + } + + if (NewFilterClasses & NDIS_PACKET_TYPE_BROADCAST) { + + NewReceiveControl |= SONIC_RCR_ACCEPT_BROADCAST; + + } + + } + + Adapter->ReceiveControlRegister = NewReceiveControl; + + SONIC_WRITE_PORT(Adapter, SONIC_RECEIVE_CONTROL, + Adapter->ReceiveControlRegister + ); + + if (CAM_DIRECTED_SIGNIFICANT(NewFilterClasses)) { + + Adapter->CamDescriptorArea->CamEnable |= 1; + + } else { + + Adapter->CamDescriptorArea->CamEnable &= ~1; + + } + + if (CAM_MULTICAST_SIGNIFICANT(NewFilterClasses)) { + + Adapter->CamDescriptorArea->CamEnable |= + Adapter->MulticastCamEnableBits; + + } else { + + Adapter->CamDescriptorArea->CamEnable &= 1; + + } + + // + // This will cause a LOAD_CAM interrupt when it is done. + // + + SonicStartCamReload(Adapter); + + Adapter->CurrentPacketFilter = NewFilterClasses; + + return NDIS_STATUS_PENDING; + +} + +STATIC +NDIS_STATUS +ChangeAddressDispatch( + IN PSONIC_ADAPTER Adapter, + IN UINT AddressCount, + IN CHAR Addresses[][ETH_LENGTH_OF_ADDRESS] + ) + +/*++ + +Routine Description: + + Modifies the Receive Control Register and Cam Enable registers, + then re-loads the CAM if necessary. + +Arguments: + + Adapter - The adapter. + + AddressCount - The number of addresses in Addresses + + Addresses - The new multicast address list. + +Return Value: + + NDIS_STATUS_PENDING - if the CAM was reloaded. + NDIS_STATUS_SUCCESS - otherwise. + +--*/ + +{ + + ULONG EnableBit; + NDIS_STATUS Status; + UINT i; + + // + // The first entry in the CAM is for our address. + // + + Adapter->MulticastCamEnableBits = 1; + EnableBit = 1; + + // + // Loop through, copying the addresses into the CAM. + // + + for (i=0; i<AddressCount; i++) { + + EnableBit <<= 1; + Adapter->MulticastCamEnableBits |= EnableBit; + + SONIC_LOAD_CAM_FRAGMENT( + &Adapter->CamDescriptorArea->CamFragments[i+1], + i+1, + Addresses[i] + ); + + } + + Adapter->CamDescriptorAreaSize = AddressCount + 1; + + // + // Now see if we have to worry about re-loading the + // CAM also. + // + + if (CAM_MULTICAST_SIGNIFICANT(Adapter->CurrentPacketFilter)) { + + Adapter->CamDescriptorArea->CamEnable = Adapter->MulticastCamEnableBits; + + // + // This will cause a LOAD_CAM interrupt when it is done. + // + + SonicStartCamReload(Adapter); + +#if DBG + if (SonicDbg) { + DbgPrint("Processing Address request pended\n"); + } +#endif + + + Status = NDIS_STATUS_PENDING; + + } else { + +#if DBG + if (SonicDbg) { + DbgPrint("Processing Address request succeeded\n"); + } +#endif + + Status = NDIS_STATUS_SUCCESS; + + } + + return Status; + +} + |