📄 xsusbhostapi.c
字号:
edP->CompletionParam,
hcP->HcFmNumber.rw.FrameNumber);
}
freeGeneralTransfer(tdP);
}
else { /* Iso format */
itdP = (USB_IsoTransferDescriptor_T*)tdP;
DM_CwDbgPrintf(DM_CW_USB_HOST_0, "Done iso TD %x, cc %d, cbp %x, be %x\n",
itdP,
itdP->Control.s.ConditionCode,
itdP->BufferPage0.d,
tdP->BufferEnd.p);
DM_CwDbgPrintf(DM_CW_USB_HOST_0, " PSW0 %x PSW1 %x PSW2 %x PSW3 %x\n",
itdP->OffsetPSW.PSW[0],
itdP->OffsetPSW.PSW[1],
itdP->OffsetPSW.PSW[2],
itdP->OffsetPSW.PSW[3]);
DM_CwDbgPrintf(DM_CW_USB_HOST_0, " PSW4 %x PSW5 %x PSW6 %x PSW7 %x\n",
itdP->OffsetPSW.PSW[4],
itdP->OffsetPSW.PSW[5],
itdP->OffsetPSW.PSW[6],
itdP->OffsetPSW.PSW[7]);
if (edP->CompletionFunction) {
int reason = edP->HeadP.s.Halted ? USBD_CompletionHalted :
USBD_CompletionNormal;
edP->CompletionFunction(reason,
itdP,
edP->CompletionParam,
hcP->HcFmNumber.rw.FrameNumber);
}
freeIsoTransfer(itdP);
}
}
}
}
/*----------------------------------------------------------------------
* Spoon feed TDs one per frame to the endpoint. There appear to be devices
* which can not handle the constant barrage of INs when the whole list is
* queued at once (Intel Video Phone).
*
* Observed device behaviour (Intel USB Camera):
*
* - SETUP sequence OK (ACK in following packet)
* - NAKs issued to first IN after SETUP, regardless of SOF delay. This
* continues for the whole frame until the next SOF at which time the device
* responds. Note, the PC HC does not attempt a retry on the endpoint until
* the next SOF, we continue to issue INs and get NAKs.
* - Sequence flows fine from here out, SOF -> SOF -> IN -> DATA -> ACK
* - OUT flow is fine, SOF -> SOF -> OUT -> DATA -> ACK
*
* The device seems to loose track of toggle and issues DATA1 PIDs. This
* results in a protocol violation and the HC halts the endpoint. Ouch. Of
* course it sounds like a broken client but ...
*/
static
void spoonFeedTDs(USB_EndpointDescriptor_T* edP,
USB_TransferDescriptor_T* lastP,
void * isControl)
{
int i;
USB_TransferDescriptor_T * tdP;
// Keep compiler quiet
i=0;
tdP=NULL;
return;
//
tdP = (USB_TransferDescriptor_T*)(edP->HeadP.s.HeadP << 4);
for(i=0; edP->TailP.p != lastP; i++) {
/* Wait for the start of frame
*/
while(!hcP->HcInterruptStatus.rw.StartofFrame)
/* Empty */ ;
/*
IOW_REG_BITSET(struct HcInterruptStatus_S,&hcP->HcInterruptStatus.rw,
StartofFrame,1);
*/
hcP->HcInterruptStatus.rw.StartofFrame = 1;
while(!hcP->HcInterruptStatus.rw.StartofFrame)
/* Empty */ ;
/*
IOW_REG_BITSET(struct HcInterruptStatus_S,&hcP->HcInterruptStatus.rw,
StartofFrame,1);
*/
hcP->HcInterruptStatus.rw.StartofFrame = 1;
/* Advance one descriptor
*/
edP->TailP.p = tdP->NextTD.p;
tdP = tdP->NextTD.p;
if (isControl) {
/*
IOW_REG_FIELD(struct HcCommandStatus_S,&hcP->HcCommandStatus.rw,
ControlListFilled,1);
*/
hcP->HcCommandStatus.rw.ControlListFilled = 1;
}
else {
/*
IOW_REG_FIELD(struct HcCommandStatus_S,&hcP->HcCommandStatus.rw,
BulkListFilled,1);
*/
hcP->HcCommandStatus.rw.BulkListFilled = 1;
}
}
}
/*----------------------------------------------------------------------
* Send a datagram
*/
static
UINT sendMessage(USB_EndpointDescriptor_T * edP,
void * setup,
void * buffer,
int bufSize,
int varOK,
USB_DirectionTD_T dir,
int * length)
{
USB_TransferDescriptor_T * firstP = edP->TailP.p;
USB_TransferDescriptor_T * lastP = edP->TailP.p;
USB_TransferDescriptor_T * tdP = edP->TailP.p;
void * lBuffer = buffer;
int lBufSize = bufSize;
int nextFrame, lastFrame;
int frameMatchRetry = 1000; /* 100ms */
usbxStats.controlStarts++;
DM_CwDbgPrintf(DM_CW_USB_HOST_0, "ED tail %x, head %x\n", edP->TailP.p, edP->HeadP.p);
edP->TotalTransferBytes = 0;
edP->TotalOutstandingTD = 0;
/* If this is a setup message send the first packet
*/
if (setup) {
tdP->Control.s.Direction_PID = UsbTDSetup;
tdP->Control.s.DelayInterrupt = USB_NoInterrupt;
tdP->Control.s.DataToggle = USB_SetupToggle;
tdP->Control.s.ConditionCode = UsbNotAccessed;
tdP->Control.s.BufferRounding = USBD_VarNotOK;
tdP->Control.s.EndpointId = edP->Control.s.EndpointId;
tdP->CurrentBufferPointer.p = setup;
tdP->BufferEnd.p = (char*)setup + 7;
if ((tdP->NextTD.p = newGeneralTransfer()) == NULL)
{
usbxStats.noTransfer++;
LOGERRORX(UsbHost.loggedError, ERR_L_USB, ERR_S_XSUSB_SENDMESSAGE, 1, ERR_T_NOTRANSFER,
usbxStats.noTransfer, 0, 0);
return UsbHost.loggedError;
}
lastP = tdP;
tdP = tdP->NextTD.p;
edP->TotalOutstandingTD++;
{
char * p = (char*)setup;
DM_CwDbgPrintf(DM_CW_USB_HOST_0, "%08X %02X %02X %02X %02X %02X %02X %02X %02X\n",
setup,
p[0],p[1],p[2],p[3],
p[4],p[5],p[6],p[7]);
}
}
/* Loop and build the data packets for the message body (if any). The
* packets must be larger or equal to the maximum packet size for the
* endpoint (endpoint processing will halt otherwise).
*/
if (lBufSize || (setup == NULL)) {
int bytes;
int toggle = USB_SetupDataToggle;
while(lBufSize > 0) {
bytes = lBufSize;
if (bytes > edP->Control.s.MaximumPacketSize)
bytes = edP->Control.s.MaximumPacketSize;
tdP->Control.s.Direction_PID = dir;
tdP->Control.s.DelayInterrupt = USB_NoInterrupt;
/* Setup data must follow the toggle rules, however, we'll force the
* ordering because we always start with DATA1.
*/
if (setup)
{
tdP->Control.s.DataToggle = toggle;
toggle ^= 1;
}
else
tdP->Control.s.DataToggle = USB_DataToggle;
tdP->Control.s.ConditionCode = UsbNotAccessed;
tdP->Control.s.BufferRounding = varOK;
tdP->Control.s.EndpointId = edP->Control.s.EndpointId;
tdP->Control.s.DataTransfer = 1; /* Mark for completion processing */
tdP->Control.s.ByteCount = bytes; /* Mark for completion processing */
tdP->CurrentBufferPointer.p = lBuffer;
tdP->BufferEnd.p = (char*)lBuffer + bytes-1;
if ((tdP->NextTD.p = newGeneralTransfer()) == NULL)
{
if (firstP->NextTD.p != NULL)
freeGeneralTransferList(firstP->NextTD.p);
usbxStats.noTransfer++;
LOGERRORX(UsbHost.loggedError, ERR_L_USB, ERR_S_XSUSB_SENDMESSAGE, 2, ERR_T_NOTRANSFER,
usbxStats.noTransfer, 0, 0);
return UsbHost.loggedError;
}
lastP = tdP;
tdP = tdP->NextTD.p;
edP->TotalOutstandingTD++;
lBuffer = (char*)lBuffer + bytes;
lBufSize -= edP->Control.s.MaximumPacketSize;
}
}
/* If this is a setup message send the status packet
*/
if (setup) {
if (dir == UsbTDIn)
tdP->Control.s.Direction_PID = UsbTDOut;
else
tdP->Control.s.Direction_PID = UsbTDIn;
tdP->Control.s.DelayInterrupt = USB_NoInterrupt;
tdP->Control.s.DataToggle = USB_StatusToggle;
tdP->Control.s.ConditionCode = UsbNotAccessed;
tdP->Control.s.BufferRounding = USBD_VarNotOK;
tdP->Control.s.EndpointId = edP->Control.s.EndpointId;
tdP->CurrentBufferPointer.p = NULL;
tdP->BufferEnd.p = NULL;
if ((tdP->NextTD.p = newGeneralTransfer()) == NULL)
{
if (firstP->NextTD.p != NULL)
freeGeneralTransferList(firstP->NextTD.p);
usbxStats.noTransfer++;
LOGERRORX(UsbHost.loggedError, ERR_L_USB, ERR_S_XSUSB_SENDMESSAGE, 3, ERR_T_NOTRANSFER,
usbxStats.noTransfer, 0, 0);
return UsbHost.loggedError;
}
lastP = tdP;
tdP = tdP->NextTD.p;
edP->TotalOutstandingTD++;
}
/* Enable interrupts on the last packet for synchronization
*/
lastP->Control.s.DelayInterrupt = 0;
lastP->Control.s.LastTD = 1;
#if 1
dumpTransferList(firstP);
#endif
/* Update the tail pointer and kick the host controller
*/
#if 1
edP->TailP.p = tdP;
if (setup) {
hcP->HcCommandStatus.rw.ControlListFilled = 1;
}
else {
hcP->HcCommandStatus.rw.BulkListFilled = 1;
}
#else
spoonFeedTDs(edP, tdP, setup);
#endif
/* Wait for the completion of the messages. Use the frame period to time
* the wait.
*/
nextFrame = (hccaP->HccaFrameNumber + USBX_TIMEOUT_FC) & 0xffff;
lastFrame = hccaP->HccaFrameNumber;
while ((edP->TotalOutstandingTD > 0) &&
!edP->HeadP.s.Halted &&
(debugUsbNoTimeout || /* Debug only */
(((hccaP->HccaFrameNumber & 0x8000) &&
!(nextFrame & 0x8000)) || /* Wrap */
(hccaP->HccaFrameNumber < nextFrame)))) {
/* Check for dead host controller
*/
if (hccaP->HccaFrameNumber == lastFrame) {
if (--frameMatchRetry < 0)
break;
}
else
frameMatchRetry = 1000;
if (hcP->HcInterruptStatus.rw.WritebackDoneHead)
processDoneQueue(); /* Need interlock with interrupt */
// temp
// if (loopbackMode)
// USBR_CheckLoopback();
DM_WaitUs(100);
}
/* If we did not receive all packets find out why
*/
if (edP->TotalOutstandingTD > 0)
{
DM_CwDbgPrintf(DM_CW_USB_HOST_0, "Outstanding requests, %d\n", edP->TotalOutstandingTD);
// Check the endpoint queue status
if (edP->HeadP.s.Halted)
{
DM_CwDbgPrintf(DM_CW_USB_HOST_1, "Processing on endpoint halted!\n");
LOGERRORX(UsbHost.loggedError, ERR_L_USB, ERR_S_XSUSB_SENDMESSAGE, 1, ERR_T_EPHALTED,
0, 0, 0);
clearTDs(edP); /* Side effect will clear halted */
usbxStats.halted++;
return UsbHost.loggedError;
}
/* Must have been a timeout
*/
DM_CwDbgPrintf(DM_CW_USB_HOST_1, "HccaFrameNumber, %d\n", hccaP->HccaFrameNumber);
LOGERRORX(UsbHost.loggedError, ERR_L_USB, ERR_S_XSUSB_SENDMESSAGE, 1, ERR_T_TIMEOUT,
0, 0, 0);
clearTDs(edP);
usbxStats.timeout++;
return UsbHost.loggedError;
}
*length = edP->TotalTransferBytes < USBD_BUFSIZ ? edP->TotalTransferBytes : 0;
return UsbHost.loggedError;
}
/*----------------------------------------------------------------------
* Start an isochronous transfer, assume buffers are in non cached space
*/
extern
UINT XsUsbHostStartIsoTransfer(USB_EndpointDescriptor_T * edP,
char * bufP,
int length,
USBD_CompletionCallback_T completion,
USBD_CallbackParam_T param)
{
#define ISO_FRAMES 8
USB_IsoTransferDescriptor_T * itdP = edP->TailP.ip;
int startFrame = edP->IsoStartFrame + ISO_FRAMES;
int i;
usbxStats.isoStarts++;
/* Check to see if the endpoint has halted and kick it if so.
*/
#if 0
if (edP->HeadP.s.Halted) { /* Endpoint halted ?? */
edP->HeadP.s.Halted = 0;
//return UsbdHalted;
}
#endif
if (startFrame < hcP->HcFmNumber.rw.FrameNumber+1)
startFrame = hcP->HcFmNumber.rw.FrameNumber+1;
DM_CwDbgPrintf(DM_CW_USB_HOST_0, "Start ISO %x, buf %x, frame %x, start %x\n",
itdP,
bufP,
hcP->HcFmNumber.rw.FrameNumber,
startFrame);
if (length != ISO_FRAMES * edP->Control.s.MaximumPacketSize)
{
usbxStats.badIsoBuffer++;
DM_CwDbgPrintf(DM_CW_USB_HOST_1, "Incorrect isochronous buffer length %d\n", length);
LOGERRORX(UsbHost.loggedError, ERR_L_USB, ERR_S_XSUSB_STARTISO, 1, ERR_T_UNEXPECTED,
usbxStats.badIsoBuffer, UsbdBadIsoBuffer, 0);
return UsbHost.loggedError;
}
/* Start at the end of the last descriptor if we're queuing in the
* active window, otherwise start on the next frame
*/
itdP->Control.s.StartFrame = startFrame;
itdP->Control.s.EndpointId = edP->Control.s.EndpointId;
itdP->Control.s.DelayInterrupt = 0;
itdP->Control.s.FrameCount = ISO_FRAMES-1;
itdP->Control.s.ConditionCode = UsbNotAccessed;
itdP->BufferPage0.s.BufferPage = (unsigned)bufP >> 12;
if ((itdP->NextTD.p = newIsoTransfer()) == NULL)
{
usbxStats.noTransfer++;
LOGERRORX(UsbHost.loggedError, ERR_L_USB, ERR_S_XSUSB_STARTISO, 2, ERR_T_NOTRANSFER,
usbxStats.noTransfer, UsbdNoTransfer, 0);
return UsbHost.loggedError;
}
itdP->BufferEnd.p = bufP + length - 1;
for (i=0; i < 8; i++) {
/* Note there are two encodings of UsbNotAccessed. The offset field is
* actually 13 bits, the MSB is the low bit of the condition code. We
* use UsbNotAccessed0 here and then allow the LSB to be set with the
* MSB of the offset. Interesting bit sharing ...
*
* Note also bit 12 is 0 is the offset is is page0 of the buffer, this
* is not the same as the value of the buffer's bit 12.
*/
itdP->OffsetPSW.Offset[i] = (UsbNotAccessed0 << 12) |
((unsigned)bufP & 0xfff) |
(((unsigned)bufP ^ (unsigned)itdP->BufferPage0.p) & 0x1000);
bufP += edP->Control.s.MaximumPacketSize;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -