📄 usbctrltrf.c
字号:
* USBCtrlTrfInHandler(). It takes care of managing a
* transfer over multiple USB transactions.
*
* Note: This routine works with isochronous endpoint larger than
* 256 bytes and is shown here as an example of how to deal
* with BC9 and BC8. In reality, a control endpoint can never
* be larger than 64 bytes.
*****************************************************************************/
void USBCtrlTrfTxService(void)
{
WORD byte_to_send;
/*
* First, have to figure out how many byte of data to send.
*/
if(wCount._word < EP0_BUFF_SIZE)
byte_to_send._word = wCount._word;
else
byte_to_send._word = EP0_BUFF_SIZE;
/*
* Next, load the number of bytes to send to BC9..0 in buffer descriptor
*/
ep0Bi.Stat.BC9 = 0;
ep0Bi.Stat.BC8 = 0;
ep0Bi.Stat._byte |= MSB(byte_to_send);
ep0Bi.Cnt = LSB(byte_to_send);
/*
* Subtract the number of bytes just about to be sent from the total.
*/
wCount._word = wCount._word - byte_to_send._word;
pDst.bRam = (byte*)&CtrlTrfData; // Set destination pointer
if(usb_stat.ctrl_trf_mem == _ROM) // Determine type of memory source
{
while(byte_to_send._word)
{
*pDst.bRam = *pSrc.bRom;
pDst.bRam++;
pSrc.bRom++;
byte_to_send._word--;
}//end while(byte_to_send._word)
}
else // RAM
{
while(byte_to_send._word)
{
*pDst.bRam = *pSrc.bRam;
pDst.bRam++;
pSrc.bRam++;
byte_to_send._word--;
}//end while(byte_to_send._word)
}//end if(usb_stat.ctrl_trf_mem == _ROM)
}//end USBCtrlTrfTxService
/******************************************************************************
* Function: void USBCtrlTrfRxService(void)
*
* PreCondition: pDst and wCount are setup properly.
* pSrc is always &CtrlTrfData
* usb_stat.ctrl_trf_mem is always _RAM.
* wCount should be set to 0 at the start of each control
* transfer.
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: *** This routine is only partially complete. Check for
* new version of the firmware.
*
* Note: None
*****************************************************************************/
void USBCtrlTrfRxService(void)
{
WORD byte_to_read;
MSB(byte_to_read) = 0x03 & ep0Bo.Stat._byte; // Filter out last 2 bits
LSB(byte_to_read) = ep0Bo.Cnt;
/*
* Accumulate total number of bytes read
*/
wCount._word = wCount._word + byte_to_read._word;
pSrc.bRam = (byte*)&CtrlTrfData;
while(byte_to_read._word)
{
*pDst.bRam = *pSrc.bRam;
pDst.bRam++;
pSrc.bRam++;
byte_to_read._word--;
}//end while(byte_to_read._word)
}//end USBCtrlTrfRxService
/******************************************************************************
* Function: void USBCtrlEPServiceComplete(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: This routine wrap up the ramaining tasks in servicing
* a Setup Request. Its main task is to set the endpoint
* controls appropriately for a given situation. See code
* below.
* There are three main scenarios:
* a) There was no handler for the Request, in this case
* a STALL should be sent out.
* b) The host has requested a read control transfer,
* endpoints are required to be setup in a specific way.
* c) The host has requested a write control transfer, or
* a control data stage is not required, endpoints are
* required to be setup in a specific way.
*
* Packet processing is resumed by clearing PKTDIS bit.
*
* Note: None
*****************************************************************************/
void USBCtrlEPServiceComplete(void)
{
if(ctrl_trf_session_owner == MUID_NULL)
{
/*
* If no one knows how to service this request then stall.
* Must also prepare EP0 to receive the next SETUP transaction.
*/
ep0Bo.Cnt = EP0_BUFF_SIZE;
ep0Bo.ADR = (byte*)&SetupPkt;
ep0Bo.Stat._byte = _USIE|_BSTALL;
ep0Bi.Stat._byte = _USIE|_BSTALL;
}
else // A module has claimed ownership of the control transfer session.
{
if(SetupPkt.DataDir == DEV_TO_HOST)
{
if(SetupPkt.wLength < wCount._word)
wCount._word = SetupPkt.wLength;
USBCtrlTrfTxService();
ctrl_trf_state = CTRL_TRF_TX;
/*
* Control Read:
* <SETUP[0]><IN[1]><IN[0]>...<OUT[1]> | <SETUP[0]>
* 1. Prepare OUT EP to respond to early termination
*
* NOTE:
* If something went wrong during the control transfer,
* the last status stage may not be sent by the host.
* When this happens, two different things could happen
* depending on the host.
* a) The host could send out a RESET.
* b) The host could send out a new SETUP transaction
* without sending a RESET first.
* To properly handle case (b), the OUT EP must be setup
* to receive either a zero length OUT transaction, or a
* new SETUP transaction.
*
* Since the SETUP transaction requires the DTS bit to be
* DAT0 while the zero length OUT status requires the DTS
* bit to be DAT1, the DTS bit check by the hardware should
* be disabled. This way the SIE could accept either of
* the two transactions.
*
* Furthermore, the Cnt byte should be set to prepare for
* the SETUP data (8-byte or more), and the buffer address
* should be pointed to SetupPkt.
*/
ep0Bo.Cnt = EP0_BUFF_SIZE;
ep0Bo.ADR = (byte*)&SetupPkt;
ep0Bo.Stat._byte = _USIE; // Note: DTSEN is 0!
/*
* 2. Prepare IN EP to transfer data, Cnt should have
* been initialized by responsible request owner.
*/
ep0Bi.ADR = (byte*)&CtrlTrfData;
ep0Bi.Stat._byte = _USIE|_DAT1|_DTSEN;
}
else // (SetupPkt.DataDir == HOST_TO_DEV)
{
ctrl_trf_state = CTRL_TRF_RX;
/*
* Control Write:
* <SETUP[0]><OUT[1]><OUT[0]>...<IN[1]> | <SETUP[0]>
*
* 1. Prepare IN EP to respond to early termination
*
* This is the same as a Zero Length Packet Response
* for control transfer without a data stage
*/
ep0Bi.Cnt = 0;
ep0Bi.Stat._byte = _USIE|_DAT1|_DTSEN;
/*
* 2. Prepare OUT EP to receive data.
*/
ep0Bo.Cnt = EP0_BUFF_SIZE;
ep0Bo.ADR = (byte*)&CtrlTrfData;
ep0Bo.Stat._byte = _USIE|_DAT1|_DTSEN;
}//end if(SetupPkt.DataDir == DEV_TO_HOST)
}//end if(ctrl_trf_session_owner == MUID_NULL)
/*
* PKTDIS bit is set when a Setup Transaction is received.
* Clear to resume packet processing.
*/
UCONbits.PKTDIS = 0;
}//end USBCtrlEPServiceComplete
/******************************************************************************
* Function: void USBPrepareForNextSetupTrf(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: The routine forces EP0 OUT to be ready for a new Setup
* transaction, and forces EP0 IN to be owned by CPU.
*
* Note: None
*****************************************************************************/
void USBPrepareForNextSetupTrf(void)
{
ctrl_trf_state = WAIT_SETUP; // See usbctrltrf.h
ep0Bo.Cnt = EP0_BUFF_SIZE; // Defined in usbcfg.h
ep0Bo.ADR = (byte*)&SetupPkt;
ep0Bo.Stat._byte = _USIE|_DAT0|_DTSEN; // EP0 buff dsc init, see usbmmap.h
ep0Bi.Stat._byte = _UCPU; // EP0 IN buffer initialization
}//end USBPrepareForNextSetupTrf
/** EOF usbctrltrf.c *********************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -