diff options
Diffstat (limited to 'private/ntos/ndis/irmini/irmini.c')
-rw-r--r-- | private/ntos/ndis/irmini/irmini.c | 1222 |
1 files changed, 1222 insertions, 0 deletions
diff --git a/private/ntos/ndis/irmini/irmini.c b/private/ntos/ndis/irmini/irmini.c new file mode 100644 index 000000000..bb60a2b14 --- /dev/null +++ b/private/ntos/ndis/irmini/irmini.c @@ -0,0 +1,1222 @@ +/* + ************************************************************************ + * + * IRMINI.c + * + * IRMINI Infrared Serial NDIS Miniport driver. + * + * (C) Copyright 1996 Microsoft Corp. + * + * + * (ep) + * + ************************************************************************* + */ + + +#include "irmini.h" + + +/* + * We keep a linked list of device objects + */ +IrDevice *firstIrDevice = NULL; + + + +/* + ************************************************************************* + * MiniportCheckForHang + ************************************************************************* + * + * Reports the state of the network interface card. + * + */ +BOOLEAN MiniportCheckForHang(NDIS_HANDLE MiniportAdapterContext) +{ + DBGOUT(("MiniportCheckForHang(0x%x)", (UINT)MiniportAdapterContext)); + return FALSE; +} + + +/* + ************************************************************************* + * MiniportDisableInterrupt + ************************************************************************* + * + * Disables the NIC from generating interrupts. + * + */ +VOID MiniportDisableInterrupt(NDIS_HANDLE MiniportAdapterContext) +{ + IrDevice *thisDev = CONTEXT_TO_DEV(MiniportAdapterContext); + DBGOUT(("MiniportDisableInterrupt(0x%x)", (UINT)MiniportAdapterContext)); + SetCOMInterrupts(thisDev, FALSE); +} + + +/* + ************************************************************************* + * MiniportEnableInterrupt + ************************************************************************* + * + * Enables the NIC to generate interrupts. + * + */ +VOID MiniportEnableInterrupt(IN NDIS_HANDLE MiniportAdapterContext) +{ + IrDevice *thisDev = CONTEXT_TO_DEV(MiniportAdapterContext); + DBGOUT(("MiniportEnableInterrupt(0x%x)", (UINT)MiniportAdapterContext)); + SetCOMInterrupts(thisDev, TRUE); +} + + + +/* + ************************************************************************* + * MiniportHalt + ************************************************************************* + * + * Halts the network interface card. + * + */ +VOID MiniportHalt(IN NDIS_HANDLE MiniportAdapterContext) +{ + IrDevice *thisDev = CONTEXT_TO_DEV(MiniportAdapterContext); + + DBGOUT(("MiniportHalt(0x%x)", (UINT)MiniportAdapterContext)); + + /* + * Remove this device from our global list + */ + + if (thisDev == firstIrDevice){ + firstIrDevice = firstIrDevice->next; + } + else { + IrDevice *dev; + for (dev = firstIrDevice; dev && (dev->next != thisDev); dev = dev->next){ } + if (dev){ + dev->next = dev->next->next; + } + else { + /* + * Don't omit this error check. I've seen NDIS call MiniportHalt with + * a bogus context when the system gets corrupted. + */ + DBGERR(("Bad context in MiniportHalt")); + return; + } + } + + + /* + * Now destroy the device object. + */ + DoClose(thisDev); + + NdisMDeregisterIoPortRange( thisDev->ndisAdapterHandle, + thisDev->portInfo.ioBase, + 8, + (PVOID)thisDev->mappedPortRange); + FreeDevice(thisDev); + + +} + + + + + +/* + ************************************************************************* + * MiniportSyncHandleInterrupt + ************************************************************************* + * + * This function is called from MiniportHandleInterrupt + * via NdisMSynchronizeWithInterrupt to synchronize with MiniportISR. + * This is required because the deferred procedure call (MiniportHandleInterrupt) + * shares data with MiniportISR but cannot achieve mutual exclusion with a spinlock + * because ISR's are not allowed to acquire spinlocks. + * + * This function should be called WITH DEVICE LOCK HELD, however, to synchronize + * with the rest of the miniport code (besides the ISR). + * + * The device's IRQ is masked out in the PIC while this function executes, + * so don't make calls up the stack. + * + */ +BOOLEAN MiniportSyncHandleInterrupt(PVOID MiniportAdapterContext) +{ + IrDevice *thisDev = CONTEXT_TO_DEV(MiniportAdapterContext); + + DBGOUT(("==> MiniportSyncHandleInterrupt")); + + /* + * Update .firstRcvBufIndex and .lastRcvBufIndex. + */ + while ((thisDev->firstRcvBufIndex != NO_BUF_INDEX) && + (thisDev->rcvBufs[thisDev->firstRcvBufIndex].state == STATE_FREE)){ + + if (thisDev->firstRcvBufIndex == thisDev->lastRcvBufIndex){ + thisDev->firstRcvBufIndex = thisDev->lastRcvBufIndex = NO_BUF_INDEX; + } + else { + thisDev->firstRcvBufIndex = NEXT_RCV_BUF_INDEX(thisDev->firstRcvBufIndex); + } + } + + DBGOUT(("<== MiniportSyncHandleInterrupt")); + + return TRUE; +} + + + +/* + ************************************************************************* + * DeliverFullBuffers + ************************************************************************* + * + * Deliver received packets to the protocol. + * + */ +VOID DeliverFullBuffers(IrDevice *thisDev) +{ + int rcvBufIndex = thisDev->firstRcvBufIndex; + + DBGOUT(("==> DeliverFullBuffers")); + + + + /* + * Deliver all full rcv buffers + */ + while (rcvBufIndex != NO_BUF_INDEX){ + rcvBuffer *rcvBuf = &thisDev->rcvBufs[rcvBufIndex]; + NDIS_STATUS stat; + PNDIS_BUFFER packetBuf; + SLOW_IR_FCS_TYPE fcs; + + switch (rcvBuf->state){ + + case STATE_FREE: + case STATE_PENDING: + /* + * This frame was already delivered. Just go to the next one. + */ + break; + + case STATE_FULL: + + /* + * The packet we have already has had BOFs, EOF, and + * escape-sequences removed. + * It contains an FCS code at the end, + * which we need to verify and then remove before + * delivering the frame. + * We compute the FCS on the packet with the packet FCS + * attached; this should produce the constant value GOOD_FCS. + */ + fcs = ComputeFCS(rcvBuf->dataBuf, rcvBuf->dataLen); + + if (fcs != GOOD_FCS){ + /* + * FCS Error. Drop this frame. + */ + DBGERR(("Bad FCS in DeliverFullBuffers 0x%x!=0x%x.", (UINT)fcs, (UINT)GOOD_FCS)); + rcvBuf->state = STATE_FREE; + + DBGSTAT(("Dropped %d/%d packets; packet with BAD FCS (%xh!=%xh):", + ++thisDev->packetsDropped, thisDev->packetsDropped + thisDev->packetsRcvd, fcs, GOOD_FCS)); + DBGPRINTBUF(rcvBuf->dataBuf, rcvBuf->dataLen); + break; + } + + + /* + * Remove the FCS from the end of the packet. + */ + rcvBuf->dataLen -= SLOW_IR_FCS_SIZE; + + + #ifdef DBG_ADD_PKT_ID + if (addPktIdOn){ + /* + * Remove dbg packet id. + */ + rcvBuf->dataLen -= sizeof(USHORT); + DBGOUT((" RCVing packet %xh **", (UINT)*(USHORT *)(rcvBuf->dataBuf+rcvBuf->dataLen))); + } + #endif + + /* + * The packet array is set up with its NDIS_PACKET. + * Now we need to allocate a single NDIS_BUFFER for the + * NDIS_PACKET and set the NDIS_BUFFER to the part of dataBuf + * that we want to deliver. + */ + NdisAllocateBuffer( &stat, + &packetBuf, + thisDev->bufferPoolHandle, + (PVOID)rcvBuf->dataBuf, + rcvBuf->dataLen); + if (stat != NDIS_STATUS_SUCCESS){ + DBGERR(("NdisAllocateBuffer failed")); + break; + } + NdisChainBufferAtFront(rcvBuf->packet, packetBuf); + + /* + * Fix up some other packet fields. + */ + NDIS_SET_PACKET_HEADER_SIZE(rcvBuf->packet, SLOW_IR_ADDR_SIZE + SLOW_IR_CONTROL_SIZE); + + DBGPKT(("Indicating rcv packet 0x%x.", (UINT)rcvBuf->packet)); + DBGPRINTBUF(rcvBuf->dataBuf, rcvBuf->dataLen); + + /* + * Indicate to the protocol that another packet is ready. + * Set the rcv buffer's state to PENDING first to avoid + * a race condition with NDIS's call to the return packet + * handler. + */ + rcvBuf->state = STATE_PENDING; + NdisMIndicateReceivePacket(thisDev->ndisAdapterHandle, &rcvBuf->packet, 1); + stat = NDIS_GET_PACKET_STATUS(rcvBuf->packet); + if (stat == NDIS_STATUS_PENDING){ + /* + * The packet is being delivered asynchronously. + * Leave the rcv buffer's state as PENDING; we'll + * get a callback when the transfer is complete. + * + * Do NOT step firstRcvBufIndex. + * We don't really need to break out here, + * but we will anyways just to make things simple. + * This is ok since we get this deferred interrupt callback + * for each packet anyway. It'll give the protocol a chance + * to catch up. + */ + DBGSTAT(("Rcv Pending. Rcvd %d packets", ++thisDev->packetsRcvd)); + } + else { + /* + * If there was an error, we are dropping this packet; + * otherwise, this packet was delivered synchronously. + * We can free the packet buffer and make this rcv frame + * available. + */ + NdisUnchainBufferAtFront(rcvBuf->packet, &packetBuf); + if (packetBuf){ + NdisFreeBuffer(packetBuf); + } + rcvBuf->state = STATE_FREE; + + if (stat == NDIS_STATUS_SUCCESS){ + DBGSTAT(("Rcvd %d packets", ++thisDev->packetsRcvd)); + } + else { + DBGSTAT(("Dropped %d/%d rcv packets. ", thisDev->packetsDropped++, thisDev->packetsDropped+thisDev->packetsRcvd)); + } + } + + break; + + + default: + /* + * This should never happen. + */ + DBGERR(("Bad rcv buffer state in DPC")); + break; + } + + /* + * Step the buffer index + */ + if (rcvBufIndex == thisDev->lastRcvBufIndex){ + rcvBufIndex = NO_BUF_INDEX; + } + else { + rcvBufIndex = NEXT_RCV_BUF_INDEX(rcvBufIndex); + } + } + + DBGOUT(("<== DeliverFullBuffers")); + +} + + + + +/* + ************************************************************************* + * MiniportHandleInterrupt + ************************************************************************* + * + * + * This is the deferred interrupt processing routine (DPC) which is + * optionally called following an interrupt serviced by MiniportISR. + * + */ +VOID MiniportHandleInterrupt(NDIS_HANDLE MiniportAdapterContext) +{ + IrDevice *thisDev = CONTEXT_TO_DEV(MiniportAdapterContext); + + DBGOUT(("==> MiniportHandleInterrupt(0x%x)", (UINT)MiniportAdapterContext)); + + + /* + * If we have just started receiving a packet, + * indicate media-busy to the protocol. + */ + if (thisDev->mediaBusy && !thisDev->haveIndicatedMediaBusy){ + NdisMIndicateStatus(thisDev->ndisAdapterHandle, NDIS_STATUS_MEDIA_BUSY, NULL, 0); + NdisMIndicateStatusComplete(thisDev->ndisAdapterHandle); + thisDev->haveIndicatedMediaBusy = TRUE; + } + + + /* + * Deliver all undelivered receive packets to the protocol. + */ + DeliverFullBuffers(thisDev); + + + /* + * Update the rcv queue 'first' and 'last' pointers. + * + * We cannot use a spinlock to coordinate accesses to the rcv buffers + * with the ISR, since ISR's are not allowed to acquire spinlocks. + * So instead, we synchronize with the ISR using this special mechanism. + * MiniportSyncHandleInterrupt will do our work for us with the IRQ + * masked out in the PIC. + */ + NdisMSynchronizeWithInterrupt( &thisDev->interruptObj, + MiniportSyncHandleInterrupt, + (PVOID)MiniportAdapterContext); + + + /* + * Send any pending write packets if possible. + */ + if (IsCommReadyForTransmit(thisDev)){ + PortReadyForWrite(thisDev, FALSE); + } + + DBGOUT(("<== MiniportHandleInterrupt")); +} + + + +/* + ************************************************************************* + * Configure + ************************************************************************* + * + * Read configurable parameters out of the system registry. + * + */ +BOOLEAN Configure(IrDevice *thisDev, NDIS_HANDLE WrapperConfigurationContext) +{ + NDIS_STATUS result = NDIS_STATUS_SUCCESS, stat; + NDIS_HANDLE configHandle; + PNDIS_CONFIGURATION_PARAMETER configParamPtr; + NDIS_STRING regKeyIRQString = NDIS_STRING_CONST("INTERRUPT"); + NDIS_STRING regKeyIOString = NDIS_STRING_CONST("IOADDRESS"); + NDIS_STRING regKeyIRTransceiverString = NDIS_STRING_CONST("InfraredTransceiverType"); + + DBGOUT(("Configure(0x%x)", (UINT)thisDev)); + + /* + * Set default values for configurable parameters. Default to COM1. + */ + thisDev->portInfo.irq = comPortIRQ[1]; + thisDev->portInfo.ioBase = comPortIOBase[1]; + thisDev->transceiverType = STANDARD_UART; + + NdisOpenConfiguration(&stat, &configHandle, WrapperConfigurationContext); + if (stat != NDIS_STATUS_SUCCESS){ + DBGERR(("NdisOpenConfiguration failed in Configure()")); + return FALSE; + } + +#if 1 + // BUGBUG REMOVE !!! + // (this here because reserving system resources causes problems for UART driver) + { + NDIS_STRING regKeyPortString = NDIS_STRING_CONST("PORT"); + int comPort = 1; + + /* + * Get infrared transceiver type for this connection. + */ + NdisReadConfiguration( &stat, + &configParamPtr, + configHandle, + ®KeyPortString, + NdisParameterInteger); + if (stat == NDIS_STATUS_SUCCESS){ + + comPort = (irTransceiverType)configParamPtr->ParameterData.IntegerData; + thisDev->portInfo.irq = comPortIRQ[comPort]; + thisDev->portInfo.ioBase = comPortIOBase[comPort]; + } + else { + DBGERR(("Couldn't read Com# from registry")); + } + } +#else + + /* + * Get IRQ level for this connection. + */ + NdisReadConfiguration( &stat, + &configParamPtr, + configHandle, + ®KeyIRQString, + NdisParameterInteger); + if (stat == NDIS_STATUS_SUCCESS){ + thisDev->portInfo.irq = (UINT)configParamPtr->ParameterData.IntegerData; + } + else { + DBGERR(("Couldn't read IRQ value from registry")); + } + + /* + * Get IO base address for this connection. + */ + NdisReadConfiguration( &stat, + &configParamPtr, + configHandle, + ®KeyIOString, + NdisParameterHexInteger); + if (stat == NDIS_STATUS_SUCCESS){ + thisDev->portInfo.ioBase = (UINT)configParamPtr->ParameterData.IntegerData; + } + else { + DBGERR(("Couldn't read IO value from registry")); + } +#endif + + /* + * Get infrared transceiver type for this connection. + */ + NdisReadConfiguration( &stat, + &configParamPtr, + configHandle, + ®KeyIRTransceiverString, + NdisParameterInteger); + if ((stat == NDIS_STATUS_SUCCESS) && + ((UINT)configParamPtr->ParameterData.IntegerData < NUM_TRANSCEIVER_TYPES)){ + + thisDev->transceiverType = (irTransceiverType)configParamPtr->ParameterData.IntegerData; + } + else { + DBGERR(("Couldn't read IR transceiver type from registry")); + } + + + NdisCloseConfiguration(configHandle); + + DBGOUT(("Configure done: irq=%d IO=%xh", thisDev->portInfo.irq, thisDev->portInfo.ioBase)); + return TRUE; +} + + +/* + ************************************************************************* + * MiniportInitialize + ************************************************************************* + * + * + * Initializes the network interface card. + * + * + * + */ +NDIS_STATUS MiniportInitialize ( PNDIS_STATUS OpenErrorStatus, + PUINT SelectedMediumIndex, + PNDIS_MEDIUM MediumArray, + UINT MediumArraySize, + NDIS_HANDLE NdisAdapterHandle, + NDIS_HANDLE WrapperConfigurationContext + ) +{ + UINT mediumIndex; + IrDevice *thisDev = NULL; + NDIS_STATUS retStat, result = NDIS_STATUS_SUCCESS; + + DBGOUT(("MiniportInitialize()")); + + /* + * Search the passed-in array of supported media for the IrDA medium. + */ + for (mediumIndex = 0; mediumIndex < MediumArraySize; mediumIndex++){ + if (MediumArray[mediumIndex] == NdisMediumIrda){ + break; + } + } + if (mediumIndex < MediumArraySize){ + *SelectedMediumIndex = mediumIndex; + } + else { + /* + * Didn't see the IrDA medium + */ + DBGERR(("Didn't see the IRDA medium in MiniportInitialize")); + result = NDIS_STATUS_UNSUPPORTED_MEDIA; + goto _initDone; + } + + /* + * Allocate a new device object to represent this connection. + */ + thisDev = NewDevice(); + if (!thisDev){ + return NDIS_STATUS_NOT_ACCEPTED; + } + + /* + * Allocate resources for this connection. + */ + if (!OpenDevice(thisDev)){ + DBGERR(("OpenDevice failed")); + result = NDIS_STATUS_FAILURE; + goto _initDone; + } + + + /* + * Read the system registry to get parameters like COM port number, etc. + */ + if (!Configure(thisDev, WrapperConfigurationContext)){ + result = NDIS_STATUS_FAILURE; + goto _initDone; + } + + + /* + * This call will associate our adapter handle with the wrapper's + * adapter handle. The wrapper will then always use our handle + * when calling us. We use a pointer to the device object as the context. + */ + NdisMSetAttributes ( NdisAdapterHandle, + (NDIS_HANDLE)thisDev, + FALSE, + NdisInterfaceInternal + ); + + + /* + * Tell NDIS about the range of IO space that we'll be using. + */ + retStat = NdisMRegisterIoPortRange( (PVOID)thisDev->mappedPortRange, + NdisAdapterHandle, + thisDev->portInfo.ioBase, + 8); + if (retStat != NDIS_STATUS_SUCCESS){ + DBGERR(("NdisMRegisterIoPortRange failed")); + result = NDIS_STATUS_FAILURE; + goto _initDone; + } + + + /* + * Record the NDIS wrapper's handle for this adapter, which we use + * when we call up to the wrapper. + * (This miniport's adapter handle is just thisDev, the pointer to the device object.). + */ + DBGOUT(("NDIS handle: %xh <-> IRMINI handle: %xh", (UINT)NdisAdapterHandle, (UINT)thisDev)); + thisDev->ndisAdapterHandle = NdisAdapterHandle; + + + /* + * Open COMM communication channel. + * This will let the dongle driver update its capabilities from their default values. + */ + if (!DoOpen(thisDev)){ + DBGERR(("DoOpen failed")); + result = NDIS_STATUS_FAILURE; + goto _initDone; + } + + + /* + * Register an interrupt with NDIS. + */ + retStat = NdisMRegisterInterrupt( (PNDIS_MINIPORT_INTERRUPT)&thisDev->interruptObj, + NdisAdapterHandle, + thisDev->portInfo.irq, + thisDev->portInfo.irq, + TRUE, // want ISR + TRUE, // MUST share interrupts + NdisInterruptLevelSensitive + ); + if (retStat != NDIS_STATUS_SUCCESS){ + DBGERR(("NdisMRegisterInterrupt failed")); + result = NDIS_STATUS_FAILURE; + goto _initDone; + } + + + _initDone: + if (result == NDIS_STATUS_SUCCESS){ + + /* + * Add this device object to the beginning of our global list. + */ + thisDev->next = firstIrDevice; + firstIrDevice = thisDev; + + DBGOUT(("MiniportInitialize succeeded")); + } + else { + if (thisDev){ + FreeDevice(thisDev); + } + DBGOUT(("MiniportInitialize failed")); + } + return result; + +} + + + +/* + ************************************************************************* + * QueueReceivePacket + ************************************************************************* + * + * + * + * + */ +VOID QueueReceivePacket(IrDevice *thisDev, PUCHAR *data, UINT dataLen) +{ + rcvBuffer *rcvBuf; + int nextRcvBufIndex; + + /* + * Note: We cannot use a spinlock to protect the rcv buffer structures + * in an ISR. This is ok, since we used a sync-with-isr function + * the the deferred callback routine to access the rcv buffers. + */ + + if (thisDev->firstRcvBufIndex == NO_BUF_INDEX){ + nextRcvBufIndex = 0; + rcvBuf = &thisDev->rcvBufs[0]; + } + else { + nextRcvBufIndex = NEXT_RCV_BUF_INDEX(thisDev->lastRcvBufIndex); + + if (nextRcvBufIndex == thisDev->firstRcvBufIndex){ + /* + * Buffers are all full. + */ + rcvBuf = NULL; + } + else { + rcvBuf = &thisDev->rcvBufs[nextRcvBufIndex]; + } + } + + if (rcvBuf){ + /* + * Get the COM port data into the receive buffer. + * For efficiency, we just swap pointers. + */ + PVOID tmpptr = *data; + *data = rcvBuf->dataBuf; + rcvBuf->dataBuf = tmpptr; + + rcvBuf->state = STATE_FULL; + rcvBuf->dataLen = dataLen; + + /* + * Update rcv queue pointers only if DoRcv succeeded + */ + if (thisDev->firstRcvBufIndex == NO_BUF_INDEX){ + thisDev->firstRcvBufIndex = thisDev->lastRcvBufIndex = 0; + } + else { + thisDev->lastRcvBufIndex = nextRcvBufIndex; + } + } + +} + + +/* + ************************************************************************* + * MiniportISR + ************************************************************************* + * + * + * This is the miniport's interrupt service routine (ISR). + * + * + */ +VOID MiniportISR ( PBOOLEAN InterruptRecognized, + PBOOLEAN QueueMiniportHandleInterrupt, + NDIS_HANDLE MiniportAdapterContext) +{ + + IrDevice *thisDev = CONTEXT_TO_DEV(MiniportAdapterContext); + + DBGOUT(("MiniportISR(0x%x, interrupt #%d)", (UINT)thisDev, ++thisDev->interruptCount)); + + /* + * Service the interrupt. + */ + COM_ISR(thisDev, InterruptRecognized, QueueMiniportHandleInterrupt); + + DBGOUT(("... MiniportISR done.")); + +} + + + + + +/* + ************************************************************************* + * MiniportReconfigure + ************************************************************************* + * + * + * Reconfigures the network interface card to new parameters available + * in the NDIS library configuration functions. + * + * + */ +NDIS_STATUS MiniportReconfigure ( OUT PNDIS_STATUS OpenErrorStatus, + IN NDIS_HANDLE MiniportAdapterContext, + IN NDIS_HANDLE WrapperConfigurationContext + ) +{ + IrDevice *thisDev = CONTEXT_TO_DEV(MiniportAdapterContext); + NDIS_STATUS result; + + DBGOUT(("MiniportReconfigure(0x%x)", (UINT)MiniportAdapterContext)); + + MiniportHalt(MiniportAdapterContext); + + if (Configure(thisDev, WrapperConfigurationContext)){ + result = NDIS_STATUS_SUCCESS; + } + else { + result = NDIS_STATUS_FAILURE; + } + + DBGOUT(("MiniportReconfigure")); + *OpenErrorStatus = result; + return result; +} + + +/* + ************************************************************************* + * MiniportReset + ************************************************************************* + * + * + * MiniportReset issues a hardware reset to the network interface card. + * The miniport driver also resets its software state. + * + * + */ +// BUGBUG: Arguments are reversed from as documented in April '96 MSDN! +NDIS_STATUS MiniportReset(PBOOLEAN AddressingReset, NDIS_HANDLE MiniportAdapterContext) +{ + IrDevice *dev, *thisDev = CONTEXT_TO_DEV(MiniportAdapterContext); + NDIS_STATUS result = NDIS_STATUS_SUCCESS; + + DBGOUT(("MiniportReset(0x%x)", (UINT)MiniportAdapterContext)); + + /* BUGBUG: fixed; REMOVE ??? + * Verify that the context is not bogus. + * I've seen bad contexts getting passed in when the system gets corrupted. + */ + for (dev = firstIrDevice; dev && (dev != thisDev); dev = dev->next){ } + if (!dev){ + DBGERR(("Bad context in MiniportReset")); + return NDIS_STATUS_FAILURE; + } + + DoClose(thisDev); + CloseDevice(thisDev); + OpenDevice(thisDev); + DoOpen(thisDev); + + *AddressingReset = TRUE; + + DBGOUT(("MiniportReset done.")); + return result; +} + + + + +/* + ************************************************************************* + * MiniportSend + ************************************************************************* + * + * + * Transmits a packet through the network interface card onto the medium. + * + * + * + */ +NDIS_STATUS MiniportSend( + IN NDIS_HANDLE MiniportAdapterContext, + IN PNDIS_PACKET Packet, + IN UINT Flags + ) +{ + IrDevice *thisDev = CONTEXT_TO_DEV(MiniportAdapterContext); + NDIS_STATUS result; + + DBGOUT(("MiniportSend(thisDev=0x%x)", (UINT)thisDev)); + + + + /* + * Put this packet at the end of our send queue. + * We use the packet's MiniportReserved field as the + * 'next' pointer. + */ + DBGPKT(("Queueing send packet 0x%x.", (UINT)Packet)); + if (thisDev->firstSendPacket){ + *(PNDIS_PACKET *)thisDev->lastSendPacket->MiniportReserved = Packet; + } + else { + thisDev->firstSendPacket = Packet; + } + thisDev->lastSendPacket = Packet; + *(PNDIS_PACKET *)Packet->MiniportReserved = NULL; + + + /* + * Try to send the first queued send packet. + */ + if (IsCommReadyForTransmit(thisDev)){ + BOOLEAN isSynchronousSend, xmitSucceeded; + + isSynchronousSend = (BOOLEAN)(Packet == thisDev->firstSendPacket); + + xmitSucceeded = PortReadyForWrite(thisDev, isSynchronousSend); + + if (isSynchronousSend){ + result = xmitSucceeded ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE; + } + else { + result = NDIS_STATUS_PENDING; + } + } + else { + result = NDIS_STATUS_PENDING; + } + + DBGOUT(("MiniportSend returning %s", DBG_NDIS_RESULT_STR(result))); + return result; +} + + + +/* + ************************************************************************* + * MiniportTransferData + ************************************************************************* + * + * + * Copies the contents of the received packet to a specified packet buffer. + * + * + * + */ +NDIS_STATUS MiniportTransferData ( + OUT PNDIS_PACKET Packet, + OUT PUINT BytesTransferred, + IN NDIS_HANDLE MiniportAdapterContext, + IN NDIS_HANDLE MiniportReceiveContext, + IN UINT ByteOffset, + IN UINT BytesToTransfer + ) +{ + + DBGERR(("MiniportTransferData - should not get called.")); + + /* + * We always pass the entire packet up in the indicate-receive call, + * so we will never get this callback. + * (We can't do anything but return failure anyway, + * since NdisMIndicateReceivePacket does not pass up a packet context). + */ + *BytesTransferred = 0; + return NDIS_STATUS_FAILURE; +} + + +/* + ************************************************************************* + * ReturnPacketHandler + ************************************************************************* + * + * When NdisMIndicateReceivePacket returns asynchronously, + * the protocol returns ownership of the packet to the miniport via this function. + * + */ +VOID ReturnPacketHandler(NDIS_HANDLE MiniportAdapterContext, PNDIS_PACKET Packet) +{ + IrDevice *thisDev = CONTEXT_TO_DEV(MiniportAdapterContext); + UINT rcvBufIndex; + + DBGOUT(("ReturnPacketHandler(0x%x)", (UINT)MiniportAdapterContext)); + + /* + * The rcv buffer index is cached in the MiniportReserved field of the packet. + */ + rcvBufIndex = *(UINT *)Packet->MiniportReserved; + + if (rcvBufIndex < NUM_RCV_BUFS){ + if (thisDev->rcvBufs[rcvBufIndex].state == STATE_PENDING){ + PNDIS_BUFFER ndisBuf; + + DBGPKT(("Reclaimed rcv packet 0x%x.", (UINT)Packet)); + + NdisUnchainBufferAtFront(Packet, &ndisBuf); + if (ndisBuf){ + NdisFreeBuffer(ndisBuf); + } + + thisDev->rcvBufs[rcvBufIndex].state = STATE_FREE; + } + else { + DBGERR(("Packet in ReturnPacketHandler was not PENDING.")); + } + } + else { + DBGERR(("Bad rcvBufIndex (from corrupted MiniportReserved) in ReturnPacketHandler.")); + } + + +} + + + +/* + ************************************************************************* + * SendPacketsHandler + ************************************************************************* + * + * Send an array of packets simultaneously. + * + */ +VOID SendPacketsHandler(NDIS_HANDLE MiniportAdapterContext, + PPNDIS_PACKET PacketArray, + UINT NumberofPackets) +{ + NDIS_STATUS stat; + UINT i; + + DBGOUT(("==> SendPacketsHandler(0x%x)", (UINT)MiniportAdapterContext)); + + /* + * This is a great opportunity to be lazy. + * Just call MiniportSend with each packet in sequence and + * set the result in the packet array object. + */ + for (i = 0; i < NumberofPackets; i++){ + stat = MiniportSend(MiniportAdapterContext, PacketArray[i], 0); + NDIS_SET_PACKET_STATUS(PacketArray[i], stat); + } + + DBGOUT(("<== SendPacketsHandler")); +} + + + +/* + ************************************************************************* + * AllocateCompleteHandler + ************************************************************************* + * + * Indicate completion of an NdisMAllocateSharedMemoryAsync call. + * We never call that function, so we should never get entered here. + * + */ +VOID AllocateCompleteHandler( NDIS_HANDLE MiniportAdapterContext, + PVOID VirtualAddress, + PNDIS_PHYSICAL_ADDRESS PhysicalAddress, + ULONG Length, + PVOID Context) +{ + DBGERR(("AllocateCompleteHandler - should not get called")); +} + + + + +/* + ************************************************************************* + * PortReadyForWrite + ************************************************************************* + * + * Called when COM port is ready for another write packet. + * Send the first frame in the send queue. + * + * Return TRUE iff send succeeded. + * + * NOTE: Do not call inside of interrupt context. + * + */ +BOOLEAN PortReadyForWrite(IrDevice *thisDev, BOOLEAN isSynchronousSend) +{ + BOOLEAN sendSucceeded = FALSE; + + DBGOUT(("PortReadyForWrite(dev=0x%x, %xh, %s)", + (UINT)thisDev, + thisDev->portInfo.ioBase, + (CHAR *)(isSynchronousSend ? "sync" : "async"))); + + + if (thisDev->firstSendPacket){ + PNDIS_PACKET packetToSend; + PNDIS_IRDA_PACKET_INFO packetInfo; + + /* + * Dequeue the first send packet and step the send queue. + * (We use the packet's MiniportReserved field is a 'next' pointer). + */ + packetToSend = thisDev->firstSendPacket; + thisDev->firstSendPacket = *(PNDIS_PACKET *)thisDev->firstSendPacket->MiniportReserved; + if (!thisDev->firstSendPacket){ + thisDev->lastSendPacket = NULL; + } + *(PNDIS_PACKET *)packetToSend->MiniportReserved = NULL; + + /* + * Enforce the minimum turnaround time that must transpire + * after the last receive. + */ + packetInfo = GetPacketInfo(packetToSend); + + if (packetInfo->MinTurnAroundTime){ + /* + * Don't want to call NdisStallExecution with more than + * 8 msec or it will cause a task switch. + * Make a series of calls with 8 msec or less. + */ + UINT usecToWait = packetInfo->MinTurnAroundTime; + do { + UINT usec = (usecToWait > 8000) ? 8000 : usecToWait; + NdisStallExecution(usec); + usecToWait -= usec; + } while (usecToWait > 0); + } + + /* + * See if this was the last packet before we need to change speed. + */ + if (packetToSend == thisDev->lastPacketAtOldSpeed){ + thisDev->lastPacketAtOldSpeed = NULL; + thisDev->setSpeedAfterCurrentSendPacket = TRUE; + } + + /* + * Send one packet to the COMM port. + */ + DBGPKT(("Sending packet 0x%x (0x%x).", thisDev->packetsSent++, (UINT)packetToSend)); + sendSucceeded = DoSend(thisDev, packetToSend); + + /* + * If the buffer we just sent was pending + * (i.e. we returned NDIS_STATUS_PENDING for it in MiniportSend), + * then hand the sent packet back to the protocol. + * Otherwise, we're just delivering it synchronously from MiniportSend. + */ + if (!isSynchronousSend){ + DBGOUT(("Calling NdisMSendComplete")); + NdisMSendComplete(thisDev->ndisAdapterHandle, packetToSend, + (NDIS_STATUS)(sendSucceeded ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE)); + } + + } + + + DBGOUT(("PortReadyForWrite done.")); + + return sendSucceeded; +} + + +/* + ************************************************************************* + * DriverEntry + ************************************************************************* + * + * Only include if IRMINI is a stand-alone driver. + * + */ +NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath); +#pragma NDIS_INIT_FUNCTION(DriverEntry) +NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) +{ + NTSTATUS result = STATUS_SUCCESS, stat; + NDIS_HANDLE wrapperHandle; + NDIS40_MINIPORT_CHARACTERISTICS info; + + DBGOUT(("==> IRMINI_Entry()")); + + NdisMInitializeWrapper( (PNDIS_HANDLE)&wrapperHandle, + DriverObject, + RegistryPath, + NULL + ); + DBGOUT(("Wrapper handle is %xh", (UINT)wrapperHandle)); + + info.MajorNdisVersion = (UCHAR)NDIS_MAJOR_VERSION; + info.MinorNdisVersion = (UCHAR)NDIS_MINOR_VERSION; +// info.Flags = 0; + info.CheckForHangHandler = MiniportCheckForHang; + info.HaltHandler = MiniportHalt; + info.InitializeHandler = MiniportInitialize; + info.QueryInformationHandler = MiniportQueryInformation; + info.ReconfigureHandler = MiniportReconfigure; + info.ResetHandler = MiniportReset; + info.SendHandler = MiniportSend; + info.SetInformationHandler = MiniportSetInformation; + info.TransferDataHandler = MiniportTransferData; + + info.HandleInterruptHandler = MiniportHandleInterrupt; + info.ISRHandler = MiniportISR; + info.DisableInterruptHandler = MiniportDisableInterrupt; + info.EnableInterruptHandler = MiniportEnableInterrupt; + + + /* + * New NDIS 4.0 fields + */ + info.ReturnPacketHandler = ReturnPacketHandler; + info.SendPacketsHandler = SendPacketsHandler; + info.AllocateCompleteHandler = AllocateCompleteHandler; + + + stat = NdisMRegisterMiniport( wrapperHandle, + (PNDIS_MINIPORT_CHARACTERISTICS)&info, + sizeof(NDIS_MINIPORT_CHARACTERISTICS)); + if (stat != NDIS_STATUS_SUCCESS){ + DBGERR(("NdisMRegisterMiniport failed in DriverEntry")); + result = STATUS_UNSUCCESSFUL; + goto _entryDone; + } + + _entryDone: + DBGOUT(("<== IRMINI_Entry %s", (PUCHAR)((result == NDIS_STATUS_SUCCESS) ? "succeeded" : "failed"))); + return result; + +} + + |