/***************************************************************************** * * Copyright (c) 1996-1999 Microsoft Corporation * * @doc * @module irsir.h | IrSIR NDIS Miniport Driver * @comm * *----------------------------------------------------------------------------- * * Author: Scott Holden (sholden) * * Date: 10/1/1996 (created) * * Contents: * *****************************************************************************/ #ifndef _IRSIR_H #define _IRSIR_H #define IRSIR_EVENT_DRIVEN 0 // // BINARY_COMPATIBLE = 0 is required so that we can include both // ntos.h and ndis.h (it is a flag in ndis.h). I think that it // is a flag to be binary compatible with Win95; however, since // we are using I/O manager we won't be. // #define BINARY_COMPATIBLE 0 #include #include #include #include // defines OID's #include // defines structs to access serial info #include "debug.h" #include "ioctl.h" #include "settings.h" #include "queue.h" // // NDIS version compatibility. // #define NDIS_MAJOR_VERSION 5 #define NDIS_MINOR_VERSION 0 // // Wrapper to NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO. // PNDIS_IRDA_PACKET_INFO static __inline GetPacketInfo(PNDIS_PACKET packet) { MEDIA_SPECIFIC_INFORMATION *mediaInfo; UINT size; NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(packet, &mediaInfo, &size); return (PNDIS_IRDA_PACKET_INFO)mediaInfo->ClassInformation; } // // Structure to keep track of receive packets and buffers to indicate // receive data to the protocol. // typedef struct { LIST_ENTRY linkage; PNDIS_PACKET packet; UINT dataLen; PUCHAR dataBuf; } RCV_BUFFER, *PRCV_BUFFER; // // States for receive finite state machine. // typedef enum _RCV_PROCESS_STATE { RCV_STATE_READY = 0, RCV_STATE_BOF, RCV_STATE_EOF, RCV_STATE_IN_ESC, RCV_STATE_RX } RCV_PROCESS_STATE; // // Structure to keep track of current state and information // of the receive state machine. // typedef struct _RCV_INFORMATION { RCV_PROCESS_STATE rcvState; UINT rcvBufPos; PRCV_BUFFER pRcvBuffer; }RCV_INFORMATION, *PRCV_INFORMATION; // // Serial receive buffer size??? // #define SERIAL_RECEIVE_BUFFER_LENGTH 2048 // // Serial timeouts to use. // // Keep the write timeouts same as the default. // // When the interval = MAXULONG, the timeouts behave as follows: // 1) If both constant and multiplier are 0, then the serial device // object returns immediately with whatever it has...even if // it is nothing. // 2) If constant and multiplier are not MAXULONG, then the serial device // object returns immediately if any characters are present. If nothing // is there then the device object uses the timeouts as specified. // 3) If multiplier is MAXULONG, then the serial device object returns // immediately if any characters are present. If nothing is there, the // device object will return the first character that arrives or wait // for the specified timeout and return nothing. // #define SERIAL_READ_INTERVAL_TIMEOUT MAXULONG #define SERIAL_READ_TOTAL_TIMEOUT_MULTIPLIER 0 #define SERIAL_READ_TOTAL_TIMEOUT_CONSTANT 10 #define SERIAL_WRITE_TOTAL_TIMEOUT_MULTIPLIER 0 #define SERIAL_WRITE_TOTAL_TIMEOUT_CONSTANT 0 extern SERIAL_TIMEOUTS SerialTimeoutsInit; extern SERIAL_TIMEOUTS SerialTimeoutsIdle; extern SERIAL_TIMEOUTS SerialTimeoutsActive; // // Maximum size of the name of the serial device object. // #define MAX_SERIAL_NAME_SIZE 100 // // Enumeration of primitives for the PASSIVE_LEVEL thread. // typedef enum _PASSIVE_PRIMITIVE { PASSIVE_SET_SPEED = 1, PASSIVE_RESET_DEVICE, PASSIVE_QUERY_MEDIA_BUSY, PASSIVE_CLEAR_MEDIA_BUSY, PASSIVE_HALT }PASSIVE_PRIMITIVE; typedef struct _IR_DEVICE { // // Allows the ir device object to be put on a queue. // LIST_ENTRY linkage; // // Keep track of the serial port name and device. // UNICODE_STRING serialDosName; UNICODE_STRING serialDevName; PDEVICE_OBJECT pSerialDevObj; HANDLE serialHandle; PFILE_OBJECT pSerialFileObj; // // This is the handle that the NDIS wrapper associates with a connection. // (The handle that the miniport driver associates with the connection // is just an index into the devStates array). // NDIS_HANDLE hNdisAdapter; // // The dongle interface allows us to check the tranceiver type once // and then set up the interface to allow us to init, set speed, // and deinit the dongle. // // We also want the dongle capabilities. // IR_TRANSCEIVER_TYPE transceiverType; DONGLE_INTERFACE dongle; DONGLE_CAPABILITIES dongleCaps; ULONG AllowedSpeedsMask; // // NDIS calls most of the MiniportXxx function with IRQL DISPATCH_LEVEL. // There are a number of instances where the ir device must send // requests to the serial device which may not be synchronous and // we can't block in DISPATCH_LEVEL. Therefore, we set up a thread to deal // with request which require PASSIVE_LEVEL. An event is used to signal // the thread that work is required. // LIST_ENTRY leWorkItems; NDIS_SPIN_LOCK slWorkItem; HANDLE hPassiveThread; KEVENT eventPassiveThread; KEVENT eventKillThread; // // Current speed setting, in bits/sec. // Note: This is updated when we ACTUALLY change the speed, // not when we get the request to change speed via // IrsirSetInformation. // UINT currentSpeed; // // Current link speed information. This also will maintain the // chosen speed if the protocol requests a speed change. // baudRateInfo *linkSpeedInfo; // // Maintain statistical debug info. // UINT packetsReceived; UINT packetsReceivedDropped; UINT packetsReceivedOverflow; UINT packetsSent; UINT packetsSentDropped; ULONG packetsHeldByProtocol; // // Indicates that we have received an OID_GEN_CURRENT_PACKET_FILTER // indication from the protocol. We can deliver received packets to the // protocol. // BOOLEAN fGotFilterIndication; // // The variable fMediaBusy is set TRUE any time that this miniport // driver receives a data frame. It can be reset by the protocol via // IrsirSetInformation and later checked via IrsirQueryInformation // to detect interleaving activity. // // In order to check for framing errors, when the protocol calls // IrsirSetInformation(OID_IRDA_MEDIA_BUSY), the miniport // sends an irp to the serial device object to clear the performance // statistics. When the protocol calls // IrsirQueryInformation(OID_IRDA_MEDIA_BUSY), if the miniport // hasn't sensed the media busy, the miniport will query the // serial device object for the performance statistics to check // for media busy. // // A spin lock is used to interleave access to fMediaBusy variable. // BOOLEAN fMediaBusy; NDIS_SPIN_LOCK mediaBusySpinLock; // // The variable fReceiving is used to indicate that the ir device // object in pending a receive from the serial device object. Note, // that this does NOT necessarily mean that any data is being // received from the serial device object, since we are constantly // polling the serial device object for data. // // Under normal circumstances fReceiving should always be TRUE. // However, when IrsirHalt or IrsirReset are called, the receive // has to be shut down and this variable is used to synchronize // the halt and reset handler. // BOOLEAN fReceiving; // // The variable fRequireMinTurnAround indicates whether a time // delay is required between the last byte of the last byte // of the last frame sent by ANOTHER station, and the point // at which it (the other station) is ready to receive the // first byte from THIS station. // // This variable is initially set to TRUE. Whenever this variable // is true and a send occurs, the a delay will be implemented by // a stall execution before the irp is sent to the serial // device object. // // After a transmission occurs with the min turnaround delay, this // variable is set to FALSE. Everytime data is received, the // variable is set to TRUE. // BOOLEAN fRequireMinTurnAround; // // The variable fPendingSetSpeed allows the receive completion routine // to check if the a set speed is required. // BOOLEAN fPendingSetSpeed; // // The variableis fPendingHalt/fPendingReset allows the send and receive // completion routines to complete the current pending irp and // then cleanup and stop sending irps to the serial driver. // BOOLEAN fPendingHalt; BOOLEAN fPendingReset; // // We keep an array of receive buffers so that we don't continually // need to allocate buffers to indicate packets to the protocol. // Since the protocol can retain ownership of up to eight packets // and we can be receiving some data while the protocol has // ownership of eight packets, we will allocate nine packets for // receiving. // #define NUM_RCV_BUFS 14 RCV_BUFFER rcvBufs[NUM_RCV_BUFS]; // // Handles to the NDIS packet pool and NDIS buffer pool // for allocating the receive buffers. // NDIS_HANDLE hPacketPool; NDIS_HANDLE hBufferPool; // // When we indicate a packet to the protocol, the protocol may // retain ownership until at some point (asynchronously), it calls // IrsirReturnPacket. No assumption is made about packet order. // // Therefore, we maintain a free queue and a pending queue of // receive buffers. Originally, all nine buffers are put on the // free queue. When data is being received, a receive buffer is // maintained in the RCV_INFORMATION described below. After we // indicate a full packet to the protocol and if the protocol // retains ownership of the packet, the receive buffer is queued // on the pending queue until IrsirReturnPacket is called. // // A spin lock is used to interleave access to both the free and // pending queues. There are three routines which use the // receive queues: InitializeReceive, SerialIoCompleteRead, and // IrsirReturnPacket. // LIST_ENTRY rcvFreeQueue; NDIS_SPIN_LOCK rcvQueueSpinLock; // // The rcvInfo object, allows the device to keep track of the // current receive buffer, the state of the finite state machine, // and the write position in the buffer. // RCV_INFORMATION rcvInfo; // // The send spin lock is used for both inserting and removing from the // send queue as well as checking and modifying the variable fSending. // // // Since we only want to send one packet at a time to the serial driver, // we need to queue other packets until each preceding send packet // has been completed by the serial device object. // // Therefore, we maintain a queue of send packets (if required). // The MiniportReserved element of the NDIS_PACKET is used as the // 'next' pointer. We keep a pointer to both the head and the // tail of the list to speed access to the queue. // PACKET_QUEUE SendPacketQueue; // // We will allocate irp buffers both send // and receive irps only once. // PUCHAR pSendIrpBuffer; PUCHAR pRcvIrpBuffer; // irp buffers and io status block for WaitOnMask ULONG MaskResult; IO_STATUS_BLOCK WaitIosb; // We use the following flag to indicate that a Wait has been issued // for the End of Frame character (0xc1). It's a ULONG because we // access it using InterlockedExchange() ULONG fWaitPending; PVOID pQueryInfoBuffer; BOOLEAN SerialBased; PVOID PnpNotificationEntry; // We do some timeout modulation during activity ULONG NumReads; ULONG ReadRecurseLevel; }IR_DEVICE, *PIR_DEVICE; VOID SendPacketToSerial( PVOID Context, PNDIS_PACKET Packet ); typedef VOID (*WORK_PROC)(struct _IR_WORK_ITEM *); typedef struct _IR_WORK_ITEM { PASSIVE_PRIMITIVE Prim; PIR_DEVICE pIrDevice; WORK_PROC Callback; PVOID InfoBuf; ULONG InfoBufLen; LIST_ENTRY ListEntry; } IR_WORK_ITEM, *PIR_WORK_ITEM; // // We use a pointer to the IR_DEVICE structure as the miniport's device context. // #define CONTEXT_TO_DEV(__deviceContext) ((PIR_DEVICE)(__deviceContext)) #define DEV_TO_CONTEXT(__irdev) ((NDIS_HANDLE)(__irdev)) #define IRSIR_TAG ' RIS' #define DEVICE_PREFIX L"\\DEVICE\\" #include "externs.h" #endif // _IRSIR_H