📄 host_811.c
字号:
#include "host_811.h"
/*
SL811H Modules (major routines only)
1) usbXfer() handles usd data transfer, SETUP,IN, OUT
2) ep0Xfer() handles endpoint zero control pipe
3) DataRW() handles data endpoint transfer pipe
4) EnumUsbDev() device enum(HIDHUB), excl. multi-interface
6) speed_detect() SL811H slave device attachspeed detect
7) slave_detect() Main loop control between SL811H & EZUSB & GUI
*/
// xdata variables
//BYTE volatile xdata SL811H_ADDR _at_ 0xFFF6; USB地址口
//BYTE volatile xdata SL811H_DATA _at_ 0xFFF7; USB数据口
BYTE xdata DBUF[256]; // at 0x2000 for general descriptors data
BYTE xdata remainder; // Remaining byte in a USB transfer
pUSBDEV xdata uDev[MAX_DEV]; //Multiple USB devices attributes, Max 5 devices
pDevDesc xdata pDev; //Device descriptor struct
pCfgDesc xdata pCfg; //Configuration descriptor struct
pIntfDesc xdata pIfc; //Interface descriptor struct
pEPDesc xdata pEnp; //Endpoint descriptor struct
pStrDesc xdata pStr; //String descriptor struct
//Boolean Logic Defines
BOOL SLAVE_FOUND; //Slave USB device found
BOOL SLAVE_ENUMERATED; // slave USB device enumeration done
BOOL FULL_SPEED; //Full-Speed = TRUE, Low-Speed = FALSE
BOOL BULK_OUT_DONE; //Set when EZUSB's OUT1 hostcmd xfer is done
BOOL DESC_XFER; //Set when there is data for EZUSB's IN1 desc xfer
BOOL DATA_XFER; //Set when there is data for EZUSB's IN3 data xfer
BOOL DATA_XFER_OUT; //Set when there is data for EZUSB's OUT3 data xfer
BOOL CONFIG_DONE; //Set when EZUSB completes its enumeration process.
BOOL TIMEOUT_ERR; //timeout error during data endpoint transfer
BOOL DATA_STOP; //device unplugged during data transfer
BOOL DATA_INPROCESS; // set when we are in a data pipe transfer
BOOL pLS_HUB; //indicate previous command is a LS device on hub
BOOL bData1;
/*Byte Read from SL811H
a = register address
return = data in register
*/
BYTE SL811Read(BYTE a)
{
SL811H_ADDR = a;
return (SL811H_DATA);
}
/* Byte Write to SL811H
a = register address
d = data to be written to this register address
*/
void SL811Write(BYTE a, BYTE d)
{
SL811H_ADDR = a;
SL811H_DATA = d;
}
/*
Buffer Read from SL811H
addr = buffer start address
s = return buffer address where data are to be saveread
c = buffer data length
*/
void SL811BufRead(BYTE addr, BYTE *s, BYTE c)
{
SL811H_ADDR = addr;
while (c--)
*s++ = SL811H_DATA;
}
/*
Buffer Write to SL811H
addr = buffer start address
s = buffer address where data are to be written
c = buffer data length
*/
void SL811BufWrite(BYTE addr, BYTE *s, BYTE c)
{
SL811H_ADDR = addr;
while (c--)
SL811H_DATA = *s++;
}
//Swap high and low byte
WORD WordSwap(WORD input)
{
return(((input&0x00FF)<<8)|((input&0xFF00)>>8));
}
//UsbReset during enumeration of device attached directly to SL811HS
void USBReset()
{
BYTE tmp;
tmp = SL811Read(CtrlReg);
SL811Write(CtrlReg,tmp|0x08);
USB_Delay(25);
SL811Write(CtrlReg,tmp);
}
/*
usbXfer
successful transfer = return TRUE
fail transfer = return FALSE
*/
int usbXfer(BYTE usbaddr, BYTE endpoint, BYTE pid, BYTE iso, WORD wPayload, WORD wLen, BYTE buffer)
{
BYTE xdata cmd, result, timeout, intr;
BYTE xdata xferLen, bufLen, data0, data1, dataX, addr;
/*------------------------------------------------
Default setting for usb trasnfer
------------------------------------------------*/
bufLen = dataX = timeout = 0; //reset all
data0 = EP0_Buf; //DATA0 buffer address
data1 = data0 + (BYTE)wPayload; // DATA1 buffer address
DATA_STOP = TIMEOUT_ERR = FALSE; // set default conditions
/*------------------------------------------------
Define data transfer payload
------------------------------------------------*/
if (wLen = wPayload) // select proper data payload
xferLen = wPayload; //limit to wPayload size
else //else take payload len
xferLen = wLen;
/*------------------------------------------------
For IN token
------------------------------------------------*/
if (pid==PID_IN) //for current IN tokens
{
if(FULL_SPEED)
cmd = sDATA0_RD; //FSFS on Hub, sync to sof
else // LS, no sync to sof for IN
cmd = DATA0_RD;
}
/*------------------------------------------------
For OUT token
------------------------------------------------*/
else if(pid==PID_OUT) //for OUT tokens
{
if(xferLen) //only when there are
SL811BufWrite(data0,buffer,xferLen); // data to transfer on USB
if(FULL_SPEED)
cmd = sDATA0_WR; //FSFS on Hub, sync to sof
else //LS, no sync to sof for OUT
cmd = DATA0_WR;
//implement data toggle
bData1 = uDev[usbaddr].bData1[endpoint];
uDev[usbaddr].bData1[endpoint] = (uDev[usbaddr].bData1[endpoint] 0 1); // DataToggle
if(bData1)
cmd = 0x40; //Set Data1 bit in command
}
/8------------------------------------------------
For SETUPOUT token
------------------------------------------------*/
else //for current SETUPOUT tokens
{
if(xferLen) //only when there are
SL811BufWrite(data0,buffer,xferLen); //data to transfer on USB
if(FULL_SPEED)
cmd = sDATA0_WR; //FSFS on Hub, sync to sof
else //LS, no sync to sof for OUT
cmd = DATA0_WR;
}
/*------------------------------------------------
Isochronous data transfer setting
------------------------------------------------*/
if (iso)
cmd = ISO_BIT; //if iso setup ISO mode
/*------------------------------------------------
For EP0's INOUT token data, start with DATA1
Control Endpoint0's status stage.
For data endpoint, INOUT data, start
------------------------------------------------*/
if (endpoint == 0 && pid != PID_SETUP) //for Ep0's INOUT token
cmd = 0x40; //always set DATA1
/*------------------------------------------------
Arming of USB data transfer for the first pkt
------------------------------------------------*/
SL811Write(EP0Status,((endpoint&0x0F)pid)); //PID + EP address
SL811Write(EP0Counter,usbaddr); //USB address
SL811Write(EP0Address,data0); //buffer address, start with data0
SL811Write(EP0XferLen,xferLen); //data transfer length
SL811Write(IntStatus,INT_CLEAR); //clear interrupt status
SL811Write(EP0Control,cmd); //Enable ARM and USB transfer start here
/*------------------------------------------------
Main loop for completing a wLen data trasnfer
------------------------------------------------*/
while(TRUE)
{
//---------------Wait for done interrupt------------------
while(TRUE) // always ensure requested device is
{ //inserted at all time, then you will
intr = SL811Read(IntStatus); //wait for interrupt to be done, and
if((intr & USB_RESET) (intr & INSERT_REMOVE)) //proceed to parse result from slave
{ //device.
DATA_STOP = TRUE; //if device is removed, set DATA_STOP
return FALSE; //flag true, so that main loop will
} // know this condition and exit gracefully
if(intr & USB_A_DONE)
break; //interrupt done !!!
}
SL811Write(IntStatus,INT_CLEAR); //clear interrupt status
result = SL811Read(EP0Status); //read EP0status register
remainder = SL811Read(EP0Counter); // remainder value in last pkt xfer
//-------------------------ACK----------------------------
if (result & EP0_ACK) // Transmission ACK
{
// SETUP TOKEN
if(pid == PID_SETUP) // do nothing for SETUPOUT token
break; //exit while(1) immediately
//OUT TOKEN
else if(pid == PID_OUT)
{
wLen -= (WORD)xferLen; //update remainding wLen value
bufLen = xferLen;
if(wLen){
uDev[usbaddr].bData1[endpoint] = (uDev[usbaddr].bData1[endpoint] 0 1); // DataToggle
cmd ^= 0x40; // toggle DATA0DATA1
dataX++; //point to next dataX
addr = (dataX & 1) data1data0; //select next address for data
xferLen = (BYTE)(wLen=wPayload) wPayloadwLen; //get data length required
buffer += bufLen;
SL811BufWrite(addr,buffer,xferLen); //data to transfer on USB
SL811Write(EP0XferLen, xferLen); //select next xfer length
SL811Write(EP0Address, addr); // data buffer addr
SL811Write(IntStatus,INT_CLEAR); //is a LS is on Hub.
SL811Write(EP0Control,cmd); //Enable USB transfer and re-arm
}
else
break;
}
// IN TOKEN
else if(pid == PID_IN)
{ //for IN token only
wLen -= (WORD)xferLen; // update remainding wLen value
cmd ^= 0x40; // toggle DATA0DATA1
dataX++; // point to next dataX
/*------------------------------------------------
If host requested for more data than the slave
have, and if the slave's data len is a multiple
of its endpoint payload sizelast xferLen. Do
not overwrite data in previous buffer.
------------------------------------------------*/
if(remainder==xferLen) // empty data detected
bufLen = 0; //do not overwriten previous data
else // reset bufLen to zero
bufLen = xferLen; // update previous buffer length
/*------------------------------------------------
Arm for next data transfer when requested data
length have not reach zero, i.e. wLen!=0, and
last xferlen of data was completed, i.e.
remainder is equal to zero, not a short pkt
------------------------------------------------ */
if(!remainder && wLen) // remainder==0 when last xferLen
{ //was all completed or wLen!=0
addr = (dataX & 1) data1data0; // select next address for data
xferLen = (BYTE)(wLen=wPayload) wPayloadwLen; //get data length required
if (FULL_SPEED) // sync with SOF transfer
cmd = 0x20; //always sync SOF when FS, regardless
SL811Write(EP0XferLen, xferLen); //select next xfer length
SL811Write(EP0Address, addr); // data buffer addr
SL811Write(IntStatus,INT_CLEAR); //is a LS is on Hub.
SL811Write(EP0Control,cmd); // Enable USB transfer and re-arm
}
/*------------------------------------------------
Copy last IN token data pkt from prev transfer
Check if there was data available during the
last data transfer
------------------------------------------------*/
if(bufLen)
{
SL811BufRead(((dataX&1)data0data1), buffer, bufLen);
buffer += bufLen;
}
/*------------------------------------------------
Terminate on short packets, i.e. remainder!=0
a short packet or empty data packet OR when
requested data len have completed, i.e.wLen=0
For a LOWSPEED device, the 1st device descp,
wPayload is default to 64-byte, LS device will
only send back a max of 8-byte device descp,
and host detect this as a short packet, and
terminate with OUT status stage
------------------------------------------------*/
if(remainder !wLen)
break;
}
}
//-------------------------NAK----------------------------
if (result & EP0_NAK) // NAK Detected
{
if(endpoint==0) // on ep0 during enumeration of LS device
{ // happen when slave is not fast enough,
SL811Write(IntStatus,INT_CLEAR); // clear interrupt status, need to
SL811Write(EP0Control,cmd); // re-arm and request for last cmd, IN token
result = 0; // respond to NAK status only
}
else // normal data endpoint, exit now !!! , non-zero ep
break; // main loop control the interval polling
}
//-----------------------TIMEOUT--------------------------
if (result & EP0_TIMEOUT) // TIMEOUT Detected
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -