⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 portemu.cxx

📁 三星2440原版bsp
💻 CXX
📖 第 1 页 / 共 5 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
//------------------------------------------------------------------------------
// 
//      Bluetooth Virtual Comm Port
// 
// 
// Module Name:
// 
//      portemu.cxx
// 
// Abstract:
// 
//      This file implements vCOMM port layer
// 
// 
//------------------------------------------------------------------------------
#include <windows.h>
#include <svsutil.hxx>
#include <bt_buffer.h>
#include <bt_ddi.h>
#include <bt_api.h>
#include <bt_debug.h>
#include <bt_sdp.h>
#include <bthapi.h>
#include <ceport.h>
#include <sdplib.h>

#include <bt_os.h>

#include <windev.h>
#include <pegdser.h>

#define EA_BIT				0x01

#define BIT(c) (1 << (c))

#define MSC_EA_BIT      EA_BIT
#define MSC_FC_BIT      BIT(1)      // Flow control, clear if we can receive
#define MSC_RTC_BIT     BIT(2)      // Ready to communicate, set when ready
#define MSC_RTR_BIT     BIT(3)      // Ready to receive, set when ready
#define MSC_IC_BIT      BIT(6)      // Incoming call
#define MSC_DV_BIT      BIT(7)      // Data valid

#define PORTEMU_OPEN_MASK		0x3
#define PORTEMU_OPEN_MAX		4	// Must be power of 2; x - 1 used for mask
#define PORTEMU_OPEN_ALLUSED	((1 << PORTEMU_OPEN_MAX) - 1)

#define PORTEMU_MAX_RFCOMM_CHANNEL	31

#define PORTEMU_OPEN_ATTEMPTS		5
#define PORTEMU_OPEN_TIMEOUT		1000

enum COMM_OP {
	COMM_NO_OP      = 0,
	COMM_OPEN       = 1,
	COMM_WAIT_EVENT = 2,
	COMM_READ       = 3,
	COMM_WRITE      = 4,
	COMM_RPN        = 5,
	COMM_DISC		= 6
};

struct PendingIO : public SVSAllocClass {
	PendingIO		*pNext;			// Next in list
	HANDLE			hEvent;			// Event to signal on completion
	COMM_OP			op;				// COMM_OP (open, wait event, read, write)

	unsigned char	*buffer;		// Buffer
	int				cbuffer;		// Size of buffer
	DWORD			dwPerms;		// Permissions

	int				cbuffer_used;	// Bytes used in the buffer so far
	int				iIoResult;		// IO result on completion

	DWORD			dwEvent;		// COMM events
	DWORD			dwLineError;	// COMM line errors

	int				iPortNum;		// Port number for this IO

	PendingIO (COMM_OP a_op, int a_iPortNum);
	~PendingIO (void);
};

enum RFCOMM_OP {
	NO_OP          = 0,
	RFCOMM_CONNECT = 1,
	RFCOMM_SDP     = 2,
	RFCOMM_PN      = 3,
	RFCOMM_WRITE   = 4,
	RFCOMM_RPN     = 5,
	RFCOMM_DISC    = 6
};

struct PORTEMU_CONTEXT;

struct ECall {
	ECall			*pNext;			// Next in list

	RFCOMM_OP		fWhat;			// RFCOMM_OP (connect or write)

	int				cBytes;			// Number of bytes on write

	PORTEMU_CONTEXT	*pContext;		// Owner context

	ECall (RFCOMM_OP a_fWhat, PORTEMU_CONTEXT *a_pContext) {
		fWhat    = a_fWhat;
		pContext = a_pContext;
		pNext    = NULL;
		cBytes   = 0;
	}

	void *operator new (size_t size);
	void operator delete (void *ptr);
};

struct BD_BUFFER_LIST {
	BD_BUFFER_LIST	*pNext;			// Next in list
	BD_BUFFER		*pb;			// Buffer

	void *operator new (size_t size);
	void operator delete (void *ptr);
};

//	This structure is what describes the device. Several important notes.
//	Lifecycle starts with registering device and ends with unregistering it.
//	The port is connected when it is opened, and disconnected when it's closed.
//	Ownership only commences with OPENING the device. Ownership is surrendered
//	by CLOSING device. When device is unowned, the com port can be configured
//	using the following call:
//		RFCOMMSetServerChannel (int index,  int channel, int flocal, BD_ADDR *pdevice, int iminmtu, int imaxmtu);
//		{if (flocal) ASSERT (! pdevice);}
//
struct PORTEMU_CONTEXT : public SVSAllocClass {
	PORTEMU_CONTEXT		*pNext;				// Next in list

	HANDLE				hRFCOMM;			// RFCOMM handle

	RFCOMM_INTERFACE	rfcomm_if;			// RFCOMM interface table
	int					iDeviceHead;		// Pre-alloc in front of the buffer
	int					iDeviceTrail;		// Pre-alloc at the end of the buffer

	unsigned int		channel      : 5;	// Server channel id
	unsigned int		fLocal       : 1;	// Local channel
	unsigned int		fLocalOpen   : 1;	// Port really connected
	unsigned int		fSdpQueryOn  : 1;	// SDP query is in progress
	unsigned int		fSentXon     : 1;	// Xon sent
	unsigned int		fc           : 1;	// flow, 1 = don't send
	unsigned int		fc_aggregate : 1;	// aggregate flow, 1 = don't send
	unsigned int		credit_fc    : 1;	// use credit-based flow
	unsigned int		local_dcb    : 1;	// use local DCB, do not send RPN commands
	unsigned int		fkeep_dcd    : 1;	// keep DCD up for the duration of connection
	unsigned int		freq_auth    : 1;	// require authentication
	unsigned int        freq_encrypt : 1;	// require encryption
	unsigned int		uiOpenRef    : 4;	// Open ref field
	unsigned int		uiReadRef    : 4;	// Open ref field
	unsigned int		uiWriteRef   : 4;	// Open ref field

	unsigned int		fSending     : 1;	// in SendData
	unsigned int		fClosing	 : 1;	// Closing port
	unsigned int		fConnected   : 1;	// Connection is up

	int					iHaveCredits;		// Have credits
	int					iGaveCredits;		// Credits outstanding

	BD_ADDR				b;					// BD_ADDR of the other side

	HANDLE				hConnection;		// Connection handle (NULL = not connected)

	int					iMTU;				// Negotiated MTU

	int					iMinMTU;			// MIN MTU for negotiation
	int					iMaxMTU;			// MAX MTU for negotiation

	int					iSendQuota;			// Send quota
	int					iSendQuotaUsed;		// Used quota for send

	int					iRecvQuota;			// Recv quota
	int					iRecvQuotaUsed;		// Used recv quota

	DWORD				adwEnabledEvents[PORTEMU_OPEN_MAX];			// Enabled COMM events (SetCommEvents)
	DWORD				adwOccuredEvents[PORTEMU_OPEN_MAX];			// Occured COMM events (WaitCommEvents)
	DWORD				adwErr[PORTEMU_OPEN_MAX];					// COMM line error
	HANDLE				hOwnerProc[PORTEMU_OPEN_MAX];				// Owner proc

	unsigned char		ucv24out;	// COMM modem status on outgoing lines
	DWORD				dwModemStatusIn;	// COMM modem status on incoming lines
	PendingIO			*pops;				// list of pending io
	BD_BUFFER_LIST		*pbl;				// Arrived data list

	ECall				*pCalls;			// pending calls


	DCB					dcb;				// DCB
	COMMTIMEOUTS		ct;					// COMMTIMEOUTS

	GUID				uuidService;		//UUID of the service
	unsigned short      sdpCid;				//channel id for sdp search

	PORTEMU_CONTEXT (void) {
		memset (this, 0, sizeof(*this));
		fLocal       = TRUE;

		local_dcb               = TRUE;

		dcb.DCBlength			= sizeof(DCB);
		dcb.BaudRate			= CBR_115200;
		dcb.fBinary				= TRUE;
		dcb.fParity				= FALSE;
		dcb.fOutxCtsFlow		= FALSE;
		dcb.fOutxDsrFlow		= FALSE;
		dcb.fDtrControl			= DTR_CONTROL_DISABLE;
		dcb.fDsrSensitivity		= FALSE;
		dcb.fTXContinueOnXoff	= TRUE;
		dcb.fOutX				= FALSE;
		dcb.fInX				= FALSE;
		dcb.fErrorChar			= FALSE;
		dcb.fNull				= FALSE;
		dcb.fRtsControl         = RTS_CONTROL_DISABLE;
		dcb.fAbortOnError       = TRUE;
		dcb.XonLim				= PORTEMU_XONLIM;
		dcb.XoffLim				= PORTEMU_XOFFLIM;
		dcb.ByteSize			= 8;
		dcb.Parity				= NOPARITY;
		dcb.StopBits			= ONESTOPBIT;

		ct.ReadIntervalTimeout         = -1;
		ct.ReadTotalTimeoutConstant    = PORTEMU_RTO;
		ct.ReadTotalTimeoutMultiplier  = 0;
		ct.WriteTotalTimeoutConstant   = PORTEMU_WTO;
		ct.WriteTotalTimeoutMultiplier = 0;
	}

	~PORTEMU_CONTEXT (void);
};

class PORTEMU : public SVSAllocClass, public SVSSynch, public SVSRefObj {
public:
	PORTEMU_CONTEXT		*pPorts;				// List of ports
	FixedMemDescr		*pfmdPBL;				// FMD for buffer list
	FixedMemDescr		*pfmdCalls;				// FMD for calls

	int					iPIOBlocksUsed;			// Ref count on PIO blocks
	int					fInitialized;			// Initialized?

	int					iDefaultMTUMin;			// Default MTU Min
	int					iDefaultMTUMax;			// Default MTU Max
	int					iDefaultSendQuota;		// Default Send Quota
	int					iDefaultRecvQuota;		// Default Recv Quota

	HANDLE				hSDP;					// SDP handle
	SDP_INTERFACE		sdp_if;					// sdp interface table

	PORTEMU (void) {
		pPorts = NULL;
		pfmdPBL = NULL;
		pfmdCalls = NULL;

		iPIOBlocksUsed = 0;
		fInitialized = FALSE;

		iDefaultMTUMin = iDefaultMTUMax = 0;
		iDefaultSendQuota = iDefaultRecvQuota = 0;

		hSDP = NULL;
		memset(&sdp_if, 0, sizeof(sdp_if));
	}
};

extern "C" BOOL COM_Close (DWORD dwData);

//
//	Static data
//
static PORTEMU	*gpPORTEMU;

PendingIO::PendingIO (COMM_OP a_op, int a_iPortNum) {
	++gpPORTEMU->iPIOBlocksUsed;
	memset (this, 0, sizeof(*this));
	op = a_op;
	iPortNum = a_iPortNum;
	hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
}

PendingIO::~PendingIO (void) {
	--gpPORTEMU->iPIOBlocksUsed;
	CloseHandle (hEvent);

#if defined (DEBUG) || defined (_DEBUG)
	PORTEMU_CONTEXT *pCtx = gpPORTEMU->pPorts;
	while (pCtx) {
		PendingIO *pio = pCtx->pops;
		while (pio && (pio != this))
			pio = pio->pNext;

		SVSUTIL_ASSERT (! pio);
		pCtx = pCtx->pNext;
	}
#endif
}

static int IsSerialIOCTL (DWORD ioctl_code) {
	if (((ioctl_code >> 16) & 0xffff) == FILE_DEVICE_SERIAL_PORT)
		return TRUE;

	return FALSE;
}

#define BAUD_ARRAY_SIZE	9
static int byte_to_baud[BAUD_ARRAY_SIZE] = {CBR_2400, CBR_4800, 7200, CBR_9600, CBR_19200, CBR_38400, CBR_57600, CBR_115200, 230400};

static int BaudToByte (int baud) {
	for (int i = 0 ; i < BAUD_ARRAY_SIZE ; ++i) {
		if (byte_to_baud[i] == baud)
			return i;
	}

	IFDBG(DebugOut (DEBUG_WARN, L"[PORTEMU] ByteToBaud : baud rate translation failed, baud = %d!\n", baud));
	return -1;
}

static int VerifyDCB (DCB *pdcb) {
	if (pdcb->DCBlength != sizeof(*pdcb))
		return FALSE;

	if (-1 == BaudToByte (pdcb->BaudRate))
		return FALSE;

	if ((pdcb->ByteSize < 5) || (pdcb->ByteSize > 8))
		return FALSE;

	if ((pdcb->StopBits != ONESTOPBIT) && (pdcb->StopBits != ONE5STOPBITS))
		return FALSE;

	if (pdcb->fParity && (pdcb->Parity > 4))
		return FALSE;

	if (! pdcb->fBinary)
		return FALSE;

	if (pdcb->fOutxCtsFlow || pdcb->fOutxDsrFlow || pdcb->fDsrSensitivity ||
			(pdcb->fDtrControl != DTR_CONTROL_DISABLE) || (pdcb->fRtsControl != RTS_CONTROL_DISABLE))
		return FALSE;

	if (pdcb->fOutX || pdcb->fInX || pdcb->fErrorChar || pdcb->fNull)
		return FALSE;

	if (pdcb->XonLim < pdcb->XoffLim)
		return FALSE;

	pdcb->EofChar = pdcb->ErrorChar = pdcb->EvtChar = pdcb->XoffChar = pdcb->XonChar = 0;

	pdcb->fAbortOnError = TRUE;
	pdcb->fTXContinueOnXoff = TRUE;

	return TRUE;
}

static ECall *NewCall (RFCOMM_OP fWhat, PORTEMU_CONTEXT *pContext) { return new ECall (fWhat, pContext); }
static PORTEMU_CONTEXT *NewPORTEMU_CONTEXT (void) { return new PORTEMU_CONTEXT; }
static PendingIO *NewPendingIO (COMM_OP op, int iPortNum) { return new PendingIO (op, iPortNum); }

static 	PORTEMU_CONTEXT *GetContext (DWORD dwData) {
	PORTEMU_CONTEXT *pContext = gpPORTEMU->pPorts;
	while (pContext && (pContext != (PORTEMU_CONTEXT *)dwData))
		pContext = pContext->pNext;

	return pContext;
}

PORTEMU_CONTEXT::~PORTEMU_CONTEXT (void) {
	IFDBG(DebugOut (DEBUG_RFCOMM_TRACE, L"[PORTEMU] deleting context 0x%08x\n", this));

	while (pops) {
		PendingIO *pNext = pops->pNext;
		pops->pNext		= NULL;
		pops->iIoResult = ERROR_OPERATION_ABORTED;
		SetEvent (pops->hEvent);

		pops = pNext;
	}

	while (pCalls) {
		ECall *pNext = pCalls->pNext;
		delete pCalls;
		pCalls = pNext;
	}

	while (pbl) {
		BD_BUFFER_LIST *pbl_next = pbl->pNext;
		if (pbl->pb->pFree)
			pbl->pb->pFree (pbl->pb);

		delete pbl;

		pbl = pbl_next;
	}

	if (hRFCOMM) {
		gpPORTEMU->Unlock ();
		RFCOMM_CloseDeviceContext (hRFCOMM);
		gpPORTEMU->Lock ();
	}

}

static void ForgetPort (PORTEMU_CONTEXT *pContext, int iPort) {
	unsigned int mask = ~(1 << iPort);
	pContext->uiOpenRef &= mask;
	pContext->uiReadRef &= mask;
	pContext->uiWriteRef &= mask;
	pContext->hOwnerProc[iPort] = NULL;
}

static ECall *FindCall (void *pCallContext) {
	if (! pCallContext)
		return NULL;

	PORTEMU_CONTEXT *pContext = NULL;

	__try {
		pContext = ((ECall *)pCallContext)->pContext;
	} __except (1) {
		IFDBG(DebugOut (DEBUG_ERROR, L"FindCall excepted!\n"));
	}

	if (! pContext)
		return NULL;

	PORTEMU_CONTEXT *pC = gpPORTEMU->pPorts;
	while (pC && (pC != pContext))
		pC = pC->pNext;

	if (! pC)
		return NULL;

	ECall *pCall = pC->pCalls;
	while (pCall && (pCall != pCallContext))
		pCall = pCall->pNext;

	return pCall;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -