windows-nt/Source/XPSP1/NT/net/irda/irsir/irsir.h
2020-09-26 16:20:57 +08:00

452 lines
13 KiB
C

/*****************************************************************************
*
* 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 <ntosp.h>
#include <zwapi.h>
#include <ndis.h>
#include <ntddndis.h> // defines OID's
#include <ntddser.h> // 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