/***************************************************************************** ** ** ** COPYRIGHT (C) 2000, 2001 MKNET CORPORATION ** ** DEVELOPED FOR THE MK7100-BASED VFIR PCI CONTROLLER. ** ** ** *****************************************************************************/ /***************************************************************************** Module Name: MKMINI.C Routines: MKMiniportReturnPackets MKMiniportCheckForHang MKMiniportHalt MKMiniportShutdownHandler MKMiniportInitialize MKMiniportReset (MK7EnableInterrupt & Disable in MK7COMM.C.) DriverEntry Comments: Contains most NDIS API routines supplied to Windows by the miniport. *****************************************************************************/ #include "precomp.h" #pragma hdrstop #include "protot.h" // Globals to help debug/test PMK7_ADAPTER GAdapter; //----------------------------------------------------------------------------- // Procedure: [MKMiniportReturnPackets] // // Description: NDIS returns a previously indicated pkt by calling this routine. // // Arguments: // IN NDIS_HANDLE MiniportAdapterContext // - a context version of our Adapter pointer // IN NDIS_PACKET Packet // - the packet that is being freed // // Returns: (none) // //----------------------------------------------------------------------------- VOID MKMiniportReturnPackets( NDIS_HANDLE MiniportAdapterContext, PNDIS_PACKET Packet) { PMK7_ADAPTER Adapter; PRPD rpd; PRCB rcb; //**************************************** // - SpinLock brackets the FreeList resource. // - Recover the RPD from the returned pkt, then return // the RPD to the FreeList. //**************************************** Adapter = PMK7_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); NdisAcquireSpinLock(&Adapter->Lock); ASSERT(Packet); #if DBG GDbgStat.rxPktsRtn++; #endif rpd = *(PRPD *)(Packet->MiniportReserved); ASSERT(rpd); ProcReturnedRpd(Adapter, rpd); // 4.0.1 BOC Adapter->UsedRpdCount--; // 4.0.1 EOC NdisReleaseSpinLock(&Adapter->Lock); } //----------------------------------------------------------------------------- // Procedure: [MKMiniportCheckForHang] // // Description: This procedure does not do much for now. // // Arguments: // MiniportAdapterContext (both) - pointer to the adapter object data area // // Returns: // FALSE or TRUE //----------------------------------------------------------------------------- BOOLEAN MKMiniportCheckForHang(NDIS_HANDLE MiniportAdapterContext) { PMK7_ADAPTER Adapter; Adapter = PMK7_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); NdisAcquireSpinLock(&Adapter->Lock); // DbgPrint(" ==> Hang Check\n\r"); if (Adapter->IOMode == TX_MODE) { Adapter->HangCheck++; if (Adapter->HangCheck >= 3) { NdisReleaseSpinLock(&Adapter->Lock); return(TRUE); } } NdisReleaseSpinLock(&Adapter->Lock); return(FALSE); } //----------------------------------------------------------------------------- // Procedure: [MKMiniportHalt] // // Description: Halts our hardware. We disable interrupts as well as the hw // itself. We release other Windows resources such as allocated // memory and timers. // // Arguments: // MiniportAdapterContext - pointer to the adapter object data area. // // Returns: (none) //----------------------------------------------------------------------------- VOID MKMiniportHalt(NDIS_HANDLE MiniportAdapterContext) { PMK7_ADAPTER Adapter; BOOLEAN Cancelled; DBGFUNC(" MKMiniportHalt"); Adapter = PMK7_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); MK7DisableInterrupt(Adapter); MK7DisableIr(Adapter); Adapter->hardwareStatus = NdisHardwareStatusClosing; // check to make sure there are no outstanding transmits while(Adapter->FirstTxQueue) { PNDIS_PACKET QueuePacket = Adapter->FirstTxQueue; Adapter->NumPacketsQueued--; DequeuePacket(Adapter->FirstTxQueue, Adapter->LastTxQueue); NDIS_SET_PACKET_STATUS(QueuePacket, NDIS_STATUS_FAILURE); NdisMSendComplete( Adapter->MK7AdapterHandle, QueuePacket, NDIS_STATUS_FAILURE); } // deregister shutdown handler NdisMDeregisterAdapterShutdownHandler(Adapter->MK7AdapterHandle); // Free the interrupt object NdisMDeregisterInterrupt(&Adapter->Interrupt); NdisMCancelTimer(&Adapter->MinTurnaroundTxTimer, &Cancelled); NdisFreeSpinLock(&Adapter->Lock); // Free the entire adapter object, including the shared memory structures. FreeAdapterObject(Adapter); } //----------------------------------------------------------------------------- // Procedure: [MKMiniportShutdownHandler] // // Description: Removes an adapter instance that was previously initialized. // To Shutdown simply Disable interrupts. Since the system is shutting // down there is no need to release resources (memory, i/o space, etc.) // that the adapter instance was using. // // Arguments: // MiniportAdapterContext - pointer to the adapter object data area. // // Returns: (none) //----------------------------------------------------------------------------- VOID MKMiniportShutdownHandler(NDIS_HANDLE MiniportAdapterContext) { PMK7_ADAPTER Adapter; Adapter = PMK7_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); MK7DisableInterrupt(Adapter); } //----------------------------------------------------------------------------- // Procedure: [MKMiniportInitialize] (only single adapter support for now) // // Description: This routine is called once per supported adapter card in the // system. This routine is responsible for initializing each adapter. // This includes parsing all of the necessary parameters from the registry, // allocating and initializing shared memory structures, configuring the // MK7100 chip, registering the interrupt, etc. // // Arguments: // OpenErrorStatus (mini) - Returns more info about any failure // SelectedMediumIndex (mini) - Returns the index in MediumArray of the // medium that the miniport is using // MediumArraySize (mini) - An array of medium types that the driver // supports // MiniportAdapterHandle (mini) - pointer to the adapter object data area. // // WrapperConfigurationContext (both) - A value that we will pass to // NdisOpenConfiguration. // // // Returns: // NDIS_STATUS_SUCCESS - If the adapter was initialized successfully. // - If for some reason the adapter didn't // initialize //----------------------------------------------------------------------------- NDIS_STATUS MKMiniportInitialize(PNDIS_STATUS OpenErrorStatus, PUINT SelectedMediumIndex, PNDIS_MEDIUM MediumArray, UINT MediumArraySize, NDIS_HANDLE MiniportAdapterHandle, NDIS_HANDLE WrapperConfigurationContext) { ULONG i; NDIS_STATUS Status; PMK7_ADAPTER Adapter; NDIS_HANDLE ConfigHandle; NDIS_INTERFACE_TYPE IfType; PVOID OverrideNetAddress; MK7REG mk7reg; DBGFUNC(" MKMiniportInitialize"); //**************************************** // We're an IrDA device. Exit w/ error if type not passed in. //**************************************** for (i = 0; i < MediumArraySize; i++) { if (MediumArray[i] == NdisMediumIrda) break; } if (i == MediumArraySize) { DBGSTR(("ERROR: IrDA Media type not found.\n")); DBGLOG("=> MKMiniportInitialize (ERR): IrDA not found", 0); return (NDIS_STATUS_UNSUPPORTED_MEDIA); } *SelectedMediumIndex = i; //**************************************** // Allocate the Adapter Object, exit if error. // (Cacheable, non-paged system memory) //**************************************** Status = ALLOC_SYS_MEM(&Adapter, sizeof(MK7_ADAPTER)); if (Status != NDIS_STATUS_SUCCESS) { DBGSTR(("ERROR: ADAPTER Allocate Memory failed (Status = 0x%x)\n", Status)); DBGLOG("<= MKMiniportInitialize: (ERR - 1)", 0); return (Status); } NdisZeroMemory(Adapter, sizeof(MK7_ADAPTER)); Adapter->MK7AdapterHandle = MiniportAdapterHandle; GAdapter = Adapter; Adapter->hardwareStatus = NdisHardwareStatusInitializing; //**************************************** // Process the Registry -- Get config settings, etc. //**************************************** Status = ProcessRegistry(Adapter, WrapperConfigurationContext); if (Status != NDIS_STATUS_SUCCESS) { FreeAdapterObject(Adapter); DBGSTR(("ERROR: ProcessRegistry() \n")); DBGLOG("<= MKMiniportInitialize: (ERR - 2)", 0); return (NDIS_STATUS_FAILURE); } //**************************************** // Let NDIS know kind of driver and features we support //**************************************** IfType = NdisInterfacePci; NdisMSetAttributesEx( Adapter->MK7AdapterHandle, (NDIS_HANDLE) Adapter, 0, (ULONG) NDIS_ATTRIBUTE_DESERIALIZE | NDIS_ATTRIBUTE_BUS_MASTER, IfType ); //**************************************** // Claim the physical Adapter for this Adapter object. We call on // NdisMPciAssignResources to find our assigned resources. //**************************************** if (ClaimAdapter(Adapter, WrapperConfigurationContext) != NDIS_STATUS_SUCCESS) { FreeAdapterObject(Adapter); DBGSTR(("ERROR: No adapter detected\n")); DBGLOG("<= MKMiniportInitialize: (ERR - 3)", 0); return (NDIS_STATUS_FAILURE); } //**************************************** // Set up the MK7 register I/O mapping w/ NDIS, interrupt mode, etc. //**************************************** Status = SetupAdapterInfo(Adapter); if (Status != NDIS_STATUS_SUCCESS) { FreeAdapterObject(Adapter); DBGSTR(("ERROR: I/O Space allocation failed (Status = 0x%X)\n",Status)); DBGLOG("<= MKMiniportInitialize: (ERR - 4)", 0); return(NDIS_STATUS_FAILURE); } //**************************************** // Allocate & initialize memory/buffer needs. //**************************************** Status = AllocAdapterMemory(Adapter); if (Status != NDIS_STATUS_SUCCESS) { FreeAdapterObject(Adapter); MKLogError(Adapter, EVENT_10, NDIS_ERROR_CODE_OUT_OF_RESOURCES, 0); DBGSTR(("ERROR: Shared Memory Allocation failed (Status = 0x%x)\n", Status)); DBGLOG("<= MKMiniportInitialize: (ERR - 5)", 0); return (NDIS_STATUS_FAILURE); } // 4.1.0 Check hw version. MK7Reg_Read(Adapter, R_CFG3, &mk7reg); if ((mk7reg & 0x1000) != 0){ mk7reg &= 0xEFFF; MK7Reg_Write(Adapter, R_CFG3, mk7reg); mk7reg |= 0x1000; MK7Reg_Write(Adapter, R_CFG3, mk7reg); MK7Reg_Read(Adapter, R_CFG3, &mk7reg); if ((mk7reg & 0x1000) != 0) Adapter->HwVersion = HW_VER_1; else Adapter->HwVersion = HW_VER_2; } else{ Adapter->HwVersion = HW_VER_2; } //**************************************** // Disable interrupts while we finish with the initialization // Must AllocAdapterMemory() before you can do this. //**************************************** MK7DisableInterrupt(Adapter); //**************************************** // Register our interrupt with the NDIS wrapper, hook our interrupt // vector, & use shared interrupts for our PCI adapters //**************************************** Status = NdisMRegisterInterrupt(&Adapter->Interrupt, Adapter->MK7AdapterHandle, Adapter->MKInterrupt, Adapter->MKInterrupt, TRUE, // call ISR each time NIC interrupts TRUE, // shared irq Adapter->InterruptMode); // NdisInterruptLatched, NdisInterruptLevelSensitive if (Status != NDIS_STATUS_SUCCESS) { FreeAdapterObject(Adapter); MKLogError(Adapter, EVENT_0, NDIS_ERROR_CODE_INTERRUPT_CONNECT, (ULONG) Adapter->MKInterrupt); DBGLOG("<= MKMiniportInitialize: (ERR - 6)", 0); return (NDIS_STATUS_FAILURE); } #if DBG DbgTestInit(Adapter); #endif //**************************************** // allocate a spin lock //**************************************** NdisAllocateSpinLock(&Adapter->Lock); Adapter->HangCheck = 0; Adapter->nowReceiving=FALSE; // 4.1.0 //**************************************** // Setup and initialize the transmit and receive structures then // init the adapter //**************************************** SetupTransmitQueues(Adapter, TRUE); SetupReceiveQueues(Adapter); if (!InitializeAdapter(Adapter)) { FreeAdapterObject(Adapter); NdisMDeregisterInterrupt(&Adapter->Interrupt); DBGSTR(("ERROR: InitializeAdapter Failed.\n")); DBGLOG("<= MKMiniportInitialize: (ERR - 7)", 0); return (NDIS_STATUS_FAILURE); } //**************************************** // Register a shutdown handler //**************************************** NdisMRegisterAdapterShutdownHandler(Adapter->MK7AdapterHandle, (PVOID) Adapter, (ADAPTER_SHUTDOWN_HANDLER) MKMiniportShutdownHandler); StartAdapter(Adapter); MK7EnableInterrupt(Adapter); Adapter->hardwareStatus = NdisHardwareStatusReady; DBGSTR(("MKMiniportInitialize: Completed Init Successfully\n")); DBGLOG("<= MKMiniportInitialize", 0); return (NDIS_STATUS_SUCCESS); } //----------------------------------------------------------------------------- // RYM-5++ // Procedure: [MKMiniportReset] // // Description: Instructs the Miniport to issue a hardware reset to the // network adapter. The driver also resets its software state. this // function also resets the transmit queues. // // Arguments: // AddressingReset - TRUE if the wrapper needs to call // MiniportSetInformation to restore the addressing // information to the current values // MiniportAdapterContext - pointer to the adapter object data area. // // Returns: // NDIS_STATUS_PENDING - This function sets a timer to complete, so // pending is always returned // // (NOTE: The timer-based completion scheme has been disable by now starting // the timer. We may now want to return Success instead of Pending.) //----------------------------------------------------------------------------- NDIS_STATUS MKMiniportReset(PBOOLEAN AddressingReset, NDIS_HANDLE MiniportAdapterContext) { PMK7_ADAPTER Adapter; MK7REG mk7reg; DBGFUNC("MKMiniportReset"); Adapter = PMK7_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); NdisAcquireSpinLock(&Adapter->Lock); Adapter->hardwareStatus = NdisHardwareStatusReset; *AddressingReset = TRUE; // *** possible temporary code // *** NDIS may actually handle this Adapter->ResetInProgress = TRUE; // Disable interrupts while we re-init the transmit structures MK7DisableInterrupt(Adapter); MK7DisableIr(Adapter); // The NDIS 5 support for deserialized miniports requires that // when reset is called, the driver de-queue and fail all uncompleted // sends, and complete any uncompleted sends. Essentially we must have // no pending send requests left when we leave this routine. // we will fail all sends that we have left right now. while(Adapter->FirstTxQueue) { PNDIS_PACKET QueuePacket = Adapter->FirstTxQueue; Adapter->NumPacketsQueued--; DequeuePacket(Adapter->FirstTxQueue, Adapter->LastTxQueue); // we must release the lock here before returning control to ndis // (even temporarily like this) NdisReleaseSpinLock(&Adapter->Lock); NDIS_SET_PACKET_STATUS(QueuePacket, NDIS_STATUS_FAILURE); NdisMSendComplete( Adapter->MK7AdapterHandle, QueuePacket, NDIS_STATUS_FAILURE); NdisAcquireSpinLock(&Adapter->Lock); } // clean up all the packets we have successfully TX'd // ProcessTXInterrupt(Adapter); // Clear out our software transmit structures NdisZeroMemory((PVOID) Adapter->XmitCached, Adapter->XmitCachedSize); // Re-initialize the transmit structures ResetTransmitQueues(Adapter, FALSE); ResetReceiveQueues(Adapter); Adapter->tcbUsed = 0; NdisMSetTimer(&Adapter->MK7AsyncResetTimer, 500); // Adapter->hardwareStatus = NdisHardwareStatusReady; // Adapter->ResetInProgress = FALSE; // MK7EnableInterrupt(Adapter); // MK7EnableIr(Adapter); NdisReleaseSpinLock(&Adapter->Lock); return(NDIS_STATUS_PENDING); } //----------------------------------------------------------------------------- // Procedure: [DriverEntry] // // Description: This is the primary initialization routine for the MK7 driver. // It is simply responsible for the intializing the wrapper and registering // the adapter driver. The routine gets called once per driver, but // MKMiniportInitialize(miniport) will get called multiple times if there are // multiple adapters. // // Arguments: // DriverObject - Pointer to driver object created by the system. // RegistryPath - The registry path of this driver // // Returns: // The status of the operation, normally this will be NDIS_STATUS_SUCCESS //----------------------------------------------------------------------------- NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { NDIS_STATUS Status; NDIS_HANDLE NdisWrapperHandle; NDIS_MINIPORT_CHARACTERISTICS MKMiniportChar; DBGFUNC("MK7-DriverEntry"); DBGLOG("=> DriverEntry", 0); //**************************************** // Now we must initialize the wrapper, and then register the Miniport //**************************************** NdisMInitializeWrapper( &NdisWrapperHandle, DriverObject, RegistryPath, NULL ); NdisZeroMemory(&MKMiniportChar, sizeof(MKMiniportChar)); // Initialize the Miniport characteristics for the call to // NdisMRegisterMiniport. MKMiniportChar.MajorNdisVersion = MK7_NDIS_MAJOR_VERSION; MKMiniportChar.MinorNdisVersion = MK7_NDIS_MINOR_VERSION; MKMiniportChar.CheckForHangHandler = MKMiniportCheckForHang; MKMiniportChar.DisableInterruptHandler = MK7DisableInterrupt; MKMiniportChar.EnableInterruptHandler = MK7EnableInterrupt; MKMiniportChar.HaltHandler = MKMiniportHalt; MKMiniportChar.HandleInterruptHandler = MKMiniportHandleInterrupt; MKMiniportChar.InitializeHandler = MKMiniportInitialize; MKMiniportChar.ISRHandler = MKMiniportIsr; MKMiniportChar.QueryInformationHandler = MKMiniportQueryInformation; MKMiniportChar.ReconfigureHandler = NULL; MKMiniportChar.ResetHandler = MKMiniportReset; MKMiniportChar.SetInformationHandler = MKMiniportSetInformation; MKMiniportChar.SendHandler = NULL; MKMiniportChar.SendPacketsHandler = MKMiniportMultiSend; MKMiniportChar.ReturnPacketHandler = MKMiniportReturnPackets; MKMiniportChar.TransferDataHandler = NULL; // MKMiniportChar.AllocateCompleteHandler = D100AllocateComplete; //**************************************** // Register this driver with the NDIS wrapper // This will cause MKMiniportInitialize to be called before returning // (is this really true? -- SoftIce shows this returning before // MKMiniportInitialize() is called(?)) //**************************************** Status = NdisMRegisterMiniport( NdisWrapperHandle, &MKMiniportChar, sizeof(NDIS_MINIPORT_CHARACTERISTICS)); if (Status == NDIS_STATUS_SUCCESS) { DBGLOG("<= DriverEntry", 0); return (STATUS_SUCCESS); } DBGLOG("<= DriverEntry: Failed!", 0); return (Status); }