📄 usbdev.cpp
字号:
usbDevReq.wLength = nLen;
USB_HANDLE h = _hDevice;
LPISSUE_VENDOR_TRANSFER f = _lpUsbFuncs->lpIssueVendorTransfer;
gpsynchUsbDevice->Unlock ();
USB_TRANSFER hTransfer = f (h, NULL, NULL, USB_OUT_TRANSFER, &usbDevReq, pBuffer, NULL);
#if defined (BT_USE_CELOG)
if (g_fCeLog) {
CELOGDATAFLAGGED(TRUE, CELID_RAW_UCHAR, pBuffer, (unsigned short)nLen, 0, CELZONE_ALWAYSON, CELOG_FLAG_HCI_COMMAND_OUT);
}
#endif
gpsynchUsbDevice->Lock ();
if (! hTransfer) {
IFDBG(DebugOut(DEBUG_ERROR, L"[USB] -WritePacket : (COMMAND_PACKET) TRANSFER FAILED!\n"));
gpsynchUsbDevice->Unlock ();
return FALSE;
}
(*gpUsbDevice->_lpUsbFuncs->lpCloseTransfer)(hTransfer);
break;
}
case DATA_PACKET_ACL:
{
SVSUTIL_ASSERT(_hOutPipes[PACKET_ACL]);
USB_PIPE h = _hOutPipes[PACKET_ACL];
LPISSUE_BULK_TRANSFER f = _lpUsbFuncs->lpIssueBulkTransfer;
DWORD dwCookie = 0xffffffff;
int nAlignLen = nLen + (4 - (nLen & 3));
USBWritePacket* pPacket = gpRingBuffer->GetWritePacket(nAlignLen, &dwCookie);
if (! pPacket) {
gpsynchUsbDevice->Unlock ();
USB_TRANSFER hTransfer = f (h, NULL, NULL, USB_OUT_TRANSFER, nLen, pBuffer, NULL);
gpsynchUsbDevice->Lock ();
if (! hTransfer) {
IFDBG(DebugOut(DEBUG_ERROR, L"[USB] -WritePacket : (DATA_PACKET_ACL) TRANSFER FAILED!\n"));
gpsynchUsbDevice->Unlock ();
return FALSE;
}
(*gpUsbDevice->_lpUsbFuncs->lpCloseTransfer)(hTransfer);
}
else {
pPacket->eType = eType;
memcpy(pPacket->pBuffer, pBuffer, nLen);
UCHAR* pTmp = pPacket->pBuffer;
gpsynchUsbDevice->Unlock ();
USB_TRANSFER hTransfer = f (h, WriteNotify, (LPVOID)dwCookie, USB_OUT_TRANSFER | USB_NO_WAIT, nLen, pTmp, NULL);
gpsynchUsbDevice->Lock ();
if (! hTransfer) {
IFDBG(DebugOut(DEBUG_ERROR, L"[USB] -WritePacket : (DATA_PACKET_ACL) TRANSFER FAILED!\n"));
gpRingBuffer->CompletePacket(dwCookie, NULL);
gpsynchUsbDevice->Unlock ();
return FALSE;
}
// If transfer is already complete, close it. Otherwise, copy handle and close async.
if ((*gpUsbDevice->_lpUsbFuncs->lpIsTransferComplete)(hTransfer)) {
(*gpUsbDevice->_lpUsbFuncs->lpCloseTransfer)(hTransfer);
} else {
pPacket->hTransfer = hTransfer;
}
}
#if defined (BT_USE_CELOG)
if (g_fCeLog) {
CELOGDATAFLAGGED(TRUE, CELID_RAW_UCHAR, pBuffer, (unsigned short)nLen, 0, CELZONE_ALWAYSON, CELOG_FLAG_HCI_ACL_OUT);
}
#endif
break;
}
case DATA_PACKET_SCO:
{
USB_PIPE hPipe = _hOutPipes[PACKET_SCO];
SVSUTIL_ASSERT( (nLen / _endpSCOOut[_nScoPipeIdx].wMaxPacketSize) <= SCO_WRITE_FRAMES_PER_PACKET );
if ( (nLen / _endpSCOOut[_nScoPipeIdx].wMaxPacketSize) > SCO_WRITE_FRAMES_PER_PACKET ) {
IFDBG(DebugOut (DEBUG_ERROR, L"[USB] SCO packet len exceeds 3 frames\n"));
break;
}
DWORD dwCookie;
int nAlignLen = nLen + (4 - (nLen & 3));
USBWritePacket* pPacket = gpRingBuffer->GetWritePacket(nAlignLen, &dwCookie);
if (! pPacket) {
DWORD dwLens[SCO_WRITE_FRAMES_PER_PACKET];
for (int i = 0; i < SCO_WRITE_FRAMES_PER_PACKET; i++) {
dwLens[i] = SCO_DEFAULT_SAMPLE_SIZE;
if (i < 3) {
// First 3 packets have 1 extra byte for SCO header
dwLens[i]++;
}
}
gpsynchUsbDevice->Unlock ();
USB_TRANSFER hTransfer = _lpUsbFuncs->lpIssueIsochTransfer(
hPipe,
NULL,
NULL,
USB_OUT_TRANSFER|USB_START_ISOCH_ASAP|USB_NO_WAIT,
0,
SCO_WRITE_FRAMES_PER_PACKET,
dwLens,
pBuffer,
NULL);
gpsynchUsbDevice->Lock ();
if (! hTransfer) {
IFDBG(DebugOut(DEBUG_ERROR, L"[USB] -WritePacket : (DATA_PACKET_SCO) TRANSFER FAILED!\n"));
gpsynchUsbDevice->Unlock ();
return TRUE; // return TRUE since we can handle this gracefully
}
}
else {
pPacket->eType = eType;
memcpy(pPacket->pBuffer, pBuffer, nLen);
for (int i = 0; i < SCO_WRITE_FRAMES_PER_PACKET; i++) {
pPacket->dwLens[i] = SCO_DEFAULT_SAMPLE_SIZE;
if (i < 3) {
// First 3 packets have 1 extra byte for SCO header
pPacket->dwLens[i]++;
}
}
DWORD* pTmpLens = pPacket->dwLens;
UCHAR* pTmpBuff = pPacket->pBuffer;
gpsynchUsbDevice->Unlock ();
USB_TRANSFER hTransfer = _lpUsbFuncs->lpIssueIsochTransfer(
hPipe,
WriteNotify,
(LPVOID)dwCookie,
USB_OUT_TRANSFER|USB_START_ISOCH_ASAP|USB_NO_WAIT,
0,
SCO_WRITE_FRAMES_PER_PACKET,
pTmpLens,
pTmpBuff,
NULL);
gpsynchUsbDevice->Lock ();
if (! hTransfer) {
IFDBG(DebugOut(DEBUG_ERROR, L"[USB] -WritePacket : (DATA_PACKET_SCO) TRANSFER FAILED!\n"));
gpRingBuffer->CompletePacket(dwCookie, NULL);
gpsynchUsbDevice->Unlock ();
return TRUE; // return TRUE since we can handle this gracefully
}
// If transfer is already complete, close it. Otherwise, copy handle and close async.
if ((*gpUsbDevice->_lpUsbFuncs->lpIsTransferComplete)(hTransfer)) {
(*gpUsbDevice->_lpUsbFuncs->lpCloseTransfer)(hTransfer);
} else {
pPacket->hTransfer = hTransfer;
}
}
#if defined (BT_USE_CELOG)
if (g_fCeLog) {
CELOGDATAFLAGGED(TRUE, CELID_RAW_UCHAR, pBuffer, (unsigned short)nLen, 0, CELZONE_ALWAYSON, CELOG_FLAG_HCI_SCO_OUT);
}
#endif
break;
}
default:
IFDBG(DebugOut (DEBUG_ERROR, L"[HCI - USB] WritePacket :: Invalid code!\n"));
break;
}
gpsynchUsbDevice->Unlock ();
return TRUE;
}
int CUsbDevice::GetBuffer (int nType, int cOffset, int cNeeded, unsigned char *d, int fCleanPackets)
{
// If we remove packets from the queue, the transfer must be for the entire packet.
// The code below assumes it in calculation of how much data has been removed from the
// queue.
SVSUTIL_ASSERT ((! fCleanPackets) || (cOffset == 0));
CUsbPipe *pPipe = &_usbPipes[nType];
if (pPipe->_pPackets == NULL)
{
SVSUTIL_ASSERT (! fCleanPackets);
return FALSE;
}
PACKET *pPacket = pPipe->_pPackets;
while (pPacket)
{
if (pPacket->nSize - pPacket->nOffset > cOffset)
break;
cOffset -= pPacket->nSize - pPacket->nOffset;
if (fCleanPackets)
{
pPipe->_pPackets = pPacket->pNext;
if (! pPipe->_pPackets)
pPipe->_pLastPacket = NULL;
delete pPacket;
pPacket = pPipe->_pPackets;
}
else
pPacket = pPacket->pNext;
}
while (pPacket && cNeeded)
{
int cTransfer = pPacket->nSize - pPacket->nOffset - cOffset;
if (cTransfer > cNeeded)
cTransfer = cNeeded;
memcpy (d, pPacket->data + pPacket->nOffset + cOffset, cTransfer);
if (fCleanPackets)
{
pPipe->iTotalQueue -= cTransfer;
pPacket->nOffset += cTransfer + cOffset;
SVSUTIL_ASSERT (pPacket->nOffset <= pPacket->nSize);
if (pPacket->nOffset == pPacket->nSize)
{
pPipe->_pPackets = pPacket->pNext;
if (! pPipe->_pPackets)
pPipe->_pLastPacket = NULL;
delete pPacket;
pPacket = pPipe->_pPackets;
}
else
SVSUTIL_ASSERT (cNeeded == cTransfer);
}
else
pPacket = pPacket->pNext;
d += cTransfer;
cNeeded -= cTransfer;
cOffset = 0;
SVSUTIL_ASSERT (cNeeded >= 0);
}
if (cNeeded != 0)
{
SVSUTIL_ASSERT (! fCleanPackets);
return FALSE;
}
return TRUE;
}
int CUsbDevice::PacketSize (int nType)
{
unsigned char d[2];
CUsbPipe *pPipe = &_usbPipes[nType];
switch (nType)
{
case EVENT_ISOCH:
if (!GetBuffer(nType, 2, 1, d, FALSE))
return 0;
return d[0] + SCO_HEADER_SIZE;
case EVENT_BULK:
if (!GetBuffer(nType, 2, 2, d, FALSE))
return 0;
SVSUTIL_ASSERT (pPipe->_pPackets->nSize >= 4);
return (d[0] | (d[1] << 8)) + ACL_HEADER_SIZE;
case EVENT_INTERRUPT:
if (!GetBuffer(nType, 1, 1, d, FALSE))
return 0;
SVSUTIL_ASSERT (pPipe->_pPackets->nSize >= 3);
return d[0] + EVENT_HEADER_SIZE;
}
IFDBG(DebugOut (DEBUG_ERROR, L"[HCI] [USB] UNKNOWN PACKET ERROR!\n"));
SVSUTIL_ASSERT (0);
return 0;
}
int CUsbDevice::CompletePacket (int nType) {
#if defined (NATIVE_SEQUENCING)
int nPacketSize = PacketSize(nType);
SVSUTIL_ASSERT ((nPacketSize == 0) || (_usbPipes[nType].iTotalQueue > 0));
if ((nPacketSize == 0) || (_usbPipes[nType].iTotalQueue < nPacketSize))
return FALSE;
if ((nPacketSize <= 0) || (nPacketSize > PACKET_SIZE_R))
{
IFDBG(DebugOut(DEBUG_ERROR, L"[HCI] [USB] Packet of invalid size.\n"));
return FALSE;
}
int fRes = FALSE;
CompletedPacket *pNewPacket = (CompletedPacket *)malloc (offsetof (CompletedPacket, ucData) + nPacketSize);
if (pNewPacket) {
pNewPacket->eType = nType;
pNewPacket->cLength = nPacketSize;
pNewPacket->pNext = NULL;
fRes = GetBuffer (pNewPacket->eType, 0, pNewPacket->cLength, pNewPacket->ucData, TRUE);
if (fRes) {
if (_pLastPacket)
_pLastPacket->pNext = pNewPacket;
else
_pPacketList = pNewPacket;
_pLastPacket = pNewPacket;
} else {
SVSUTIL_ASSERT (0);
free (pNewPacket);
}
} else
SVSUTIL_ASSERT (0); //OOM
return fRes;
#else
return TRUE;
#endif
}
int CUsbDevice::RetrievePacket (unsigned char *pBuffer, int *pnLen, int *pnType, DWORD *pdwTimeout)
{
#if defined (NATIVE_SEQUENCING)
if (_pPacketList) {
*pnLen = _pPacketList->cLength;
*pnType = _pPacketList->eType;
memcpy (pBuffer, _pPacketList->ucData, _pPacketList->cLength);
CompletedPacket *pNext = _pPacketList->pNext;
free (_pPacketList);
_pPacketList = pNext;
if (! _pPacketList)
_pLastPacket = NULL;
return TRUE;
}
return FALSE;
#else
#if defined (CONNECTION_TRACKING)
// If we are tracking connections, give slight bias to bulk data
// since in processing disconnection events we need to reverse
// priorities and process data that comes slightly after the disconnect
// events...
for (int i = EVENT_ISOCH ; i <= EVENT_INTERRUPT; ++i)
#else
for (int i = EVENT_INTERRUPT ; i >= EVENT_ISOCH; --i)
#endif
{
int nPacketSize = PacketSize(i);
SVSUTIL_ASSERT ((nPacketSize == 0) || (_usbPipes[i].iTotalQueue > 0));
if ((nPacketSize == 0) || (_usbPipes[i].iTotalQueue < nPacketSize))
continue;
if ((nPacketSize <= 0) || (nPacketSize > PACKET_SIZE_R))
{
IFDBG(DebugOut(DEBUG_ERROR, L"[HCI] [USB] Packet of invalid size.\n"));
return FALSE;
}
#if defined (CONNECTION_TRACKING)
// Bulk packet reads can preceed interrupts. This would be *REALLY* bad
// if this interrupt is a connection completion event. Therefore we
// will stall data packets for 1/2 sec unless connection event has been
// received.
if (i == EVENT_BULK) {
unsigned char d[2];
if (GetBuffer (i, 0, 2, d, FALSE) &&
((GetTickCount () - _usbPipes[i]._pPackets->dwWhenReceived) <
(CONNECTION_TRACKING_TIMEOUT / 2))) {
unsigned short hConn = d[0] | ((d[1] & 0xf) << 8);
if (! _pHandleTree->Locate (hConn)) {
IFDBG(DebugOut (DEBUG_WARN, L"USB TRANSPORT: ****PACKET STALLED %d ms****\n", CONNECTION_TRACKING_TIMEOUT));
*pdwTimeout = CONNECTION_TRACKING_TIMEOUT;
continue;
}
}
}
#endif
*pnType = i;
*pnLen= nPacketSize;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -