📄 usbisr.c
字号:
/*
* usbisr.c
*
* PDIUSBD12 USB device comm's - interrupt support functions
*
* Adapted from Philips PDIUSBD12 firmware library (ISR.C)
* MJB Nov.2005
*/
#include "gendef.h"
#include "usbdef.h"
#include "usbhal.h"
#include "usbci.h"
#include "usb200.h"
#include "usbch9.h"
/*** Globals ***/
USB_FLAGS USBflags; /* USB comm's status flags (usbdef.h) */
CONTROL_XFER ControlData; /* Control endpoint TX/RX buffers */
bool USB_active; /* Device is attached */
bool USB_BulkInTxReady; /* D12 is ready to accept data for TX on EP2 */
bool USB_InterruptInTxReady; /* D12 is ready to accept data for TX on EP1 */
ushort USB_ErrorFlags[8]; /* D12 error status words, 1 per endpoint (debug usage) */
static ushort D12_int_flags; /* D12 interrupt flags register */
/*
* D12 Interrupt Service Routine
*/
_INTERRUPT_ usb_isr( void )
{
if ( USBflags.bits.in_isr ) debug_signal( BIT_13 ); /* ISR re-entered (Error) */
USBflags.bits.in_isr = 1;
D12_int_flags = D12_ReadInterruptRegister();
/*** NB: Reading the D12 Int Request Register also clears it. ***/
if ( D12_int_flags != 0 )
{
if ( D12_int_flags & D12_INT_BUSRESET ) bus_reset();
if ( D12_int_flags & D12_INT_EOT ) dma_eot();
if ( D12_int_flags & D12_INT_SUSPENDCHANGE ) suspend_change();
if ( D12_int_flags & D12_INT_ENDP0IN ) control_in_handler(); /* EP0 TX request */
if ( D12_int_flags & D12_INT_ENDP0OUT ) control_out_handler(); /* EP0 RX request */
if ( D12_int_flags & D12_INT_ENDP1IN ) interrupt_in_handler(); /* EP1 TX request */
if ( D12_int_flags & D12_INT_ENDP1OUT ) endpoint1_out_handler(); /* EP1 RX request */
if ( D12_int_flags & D12_INT_ENDP2IN ) bulk_in_handler(); /* EP2 TX request */
if ( D12_int_flags & D12_INT_ENDP2OUT ) bulk_out_handler(); /* EP2 RX request */
}
USBflags.bits.in_isr = 0;
}
/* If we need to reconnect, do this in kernel... ie poll the bus_reset flag in main loop */
void bus_reset( void )
{
USBflags.bits.bus_reset = TRUE;
}
/* DMA mode not supported. (Set a flag anyway -- for debug purposes) */
void dma_eot( void )
{
USBflags.bits.dma_eot = TRUE;
}
/* Suspend mode not supported. (Set a flag anyway -- for debug purposes) */
void suspend_change( void )
{
USBflags.bits.suspend = TRUE;
}
/*
* Control OUT handler... (EP0 RX request)
* Packet received from host via Control Endpoint EP0 OUT (index=00)
*/
void control_out_handler( void )
{
uchar status;
short len;
status = D12_ReadLastTransactionStatus(0); /* Clear interrupt flag & read status */
UpdateUSBErrorFlags( 0, status );
if ( status & D12_SETUPPACKET ) /* SETUP packet */
{
ControlData.wLength = 0;
ControlData.wCount = 0;
/* Read the control packet into ControlData.DeviceRequest... */
len = D12_ReadEndpoint( 0, (uchar *) &(ControlData.DeviceRequest),
sizeof(ControlData.DeviceRequest) );
if ( len != sizeof(DEVICE_REQUEST) )
{
/* Invalid request... stall control EP */
D12_SetEndpointStatus(0, 1);
D12_SetEndpointStatus(1, 1);
USBflags.bits.control_state = USB_IDLE;
return;
}
/* Packet format is little-endian; 68K data structure is big-endian */
ControlData.DeviceRequest.wValue = SWAP(ControlData.DeviceRequest.wValue);
ControlData.DeviceRequest.wIndex = SWAP(ControlData.DeviceRequest.wIndex);
ControlData.DeviceRequest.wLength = SWAP(ControlData.DeviceRequest.wLength);
/* Acknowledge SETUP here to unlock control in/out endpoints */
D12_AcknowledgeEndpoint( 0 );
D12_AcknowledgeEndpoint( 1 );
ControlData.wLength = ControlData.DeviceRequest.wLength;
ControlData.wCount = 0;
if ( ControlData.DeviceRequest.bmRequestType & USB_ENDPOINT_DIRECTION_MASK )
{
USBflags.bits.setup_packet = TRUE; /* 'Get' command */
USBflags.bits.control_state = USB_IDLE;
control_dispatcher();
}
else /* 'Set' command... */
{
if ( ControlData.DeviceRequest.wLength == 0 ) /* 'Set' with no data */
{
USBflags.bits.setup_packet = TRUE;
USBflags.bits.control_state = USB_IDLE;
control_dispatcher();
}
else /* 'Set' with data to follow */
{
if ( ControlData.DeviceRequest.wLength > MAX_CONTROLDATA_SIZE )
{
USBflags.bits.control_state = USB_IDLE; /* Error... stall EP0 */
D12_SetEndpointStatus(0, 1);
D12_SetEndpointStatus(1, 1);
}
else
{
USBflags.bits.control_state = USB_RECEIVE;
}
}
}
} /* if setup packet */
/* Not a SETUP packet... receiving data pkt from host... (## see note below) */
else if ( USBflags.bits.control_state == USB_RECEIVE )
{
len = D12_ReadEndpoint( 0,
(ControlData.dataBuffer + ControlData.wCount), EP0_MAX_PACKET_SIZE );
ControlData.wCount += len;
if ( ( len != EP0_MAX_PACKET_SIZE ) || ( ControlData.wCount >= ControlData.wLength ) )
{
/* Short packet or got wLength bytes already... done receiving data */
USBflags.bits.setup_packet = TRUE;
USBflags.bits.control_state = USB_IDLE;
control_dispatcher();
}
}
/* Not a SETUP pkt and not receiving data */
else { USBflags.bits.control_state = USB_IDLE; }
}
/*
* ## Note: Taken "as is" from Philips D12 firmware library, the above code is defective!
*
* 1. ControlData.dataBuffer[] was allocated 8 bytes. EP0_MAX_PACKET_SIZE is 16, but
* a Control-OUT data transfer can be up to 1024 bytes! (USB2.0 standard). Therefore,
* memory beyond &ControlData.dataBuffer[7] could be corrupted. (This doesn't happen because
* none of the currently supported Device Requests has DATA-OUT packets following.)
*
* 2. If, while receiving data packets, a short pkt is received, it is assumed to be
* a Setup pkt and the control_dispatcher() is called. Control-OUT data packets do not need
* to be EP0_MAX_PACKET_SIZE in length, so this behaviour is wrong! (see USB std)
*
* 3. If the number of DATA bytes received is ControlData.wLength, including the
* incoming pkt, the pkt is assumed to be a SETUP pkt and control_dispatcher() is called!
* (This behaviour is OK if the number of data bytes received exceeds ControlData.wLength,
* because the behaviour in this case is "undefined" by the USB 2.0 standard.)
*
* None of these deficiencies will cause any problem, except if the firmware needs to be
* extended so that Control-OUT data packets can exceed 16 bytes in length. This would
* be required if using the Control pipe to transfer data from host to device.
* (Neither the CDC nor TMC/488 protocols are affected, but other USB classes might be.)
*/
/*
* Control Dispatcher
*
* Called whenever a Device Request is received from the host via the Control-OUT endpoint.
* The Control Dispatcher differentiates between standard USB2.0 Device Requests, Vendor-
* Specific requests, and Class-specific requests, e.g. USBTMC or CDC protocol requests.
* All requests are completed inside the USB interrupt service routine, while higher priority
* ISRs may interrupt. This scheme maximises data throughput on the USB link and minimises
* delays to "application layer" tasks.
*/
void control_dispatcher( void )
{
uchar type, req;
type = ControlData.DeviceRequest.bmRequestType & USB_REQUEST_TYPE_MASK;
req = ControlData.DeviceRequest.bRequest;
if ( type == USB_STANDARD_REQUEST )
{
if ( req < NUMBER_STD_REQ ) (*StandardDeviceRequest[req])();
}
/***
else if ( type == USB_VENDOR_REQUEST )
{
if ( req < NUMBER_VENDOR_REQ ) (*VendorDeviceRequest[req])();
}
***/
else if ( type == USB_CLASS_REQUEST )
{
switch ( req )
{
/***
*
* Insert cases of Class Request handlers here (if any)...
*
***/
case CLASS_REQUEST_XYZZY: /* Example */
class_request_xyzzy_handler();
break;
default:
stall_ep0(); /* Invalid Request code */
break;
}
}
else stall_ep0();
}
/*
* Control IN handler... (EP0 TX request)
* A packet has already been transmitted to host via Control Endpoint EP0 IN (index=01).
* This function transmits the next packet in the transfer in progress, if any data remains;
* otherwise it transmits a zero-length packet (Ack handshake).
* Response to a Device Request.
*/
void control_in_handler( void )
{
uchar status;
short i = ControlData.wLength - ControlData.wCount;
status = D12_ReadLastTransactionStatus(1); /* Clear interrupt flag */
UpdateUSBErrorFlags( 1, status );
if ( USBflags.bits.control_state != USB_TRANSMIT ) /* D12 not in Transmit mode (error) */
return;
if ( i >= EP0_MAX_PACKET_SIZE ) /* More than one pkt of data remaining in EP0 buffer */
{
D12_WriteEndpoint( 1, (ControlData.pData + ControlData.wCount), EP0_MAX_PACKET_SIZE );
ControlData.wCount += EP0_MAX_PACKET_SIZE;
USBflags.bits.control_state = USB_TRANSMIT;
}
else if ( i > 0 ) /* Last non-zero size data pkt to be sent */
{
D12_WriteEndpoint( 1, (ControlData.pData + ControlData.wCount), i );
ControlData.wCount += i;
USBflags.bits.control_state = USB_IDLE;
}
else if ( i <= 0 ) /* No data left to send, or screwed up somewhere */
{
D12_WriteEndpoint( 1, (uchar *) NULL, 0 ); /* Send zero-length data packet */
USBflags.bits.control_state = USB_IDLE;
}
}
/*
* Endpoint 1 OUT Handler... (EP1 RX request)
* Packet received from host via Endpoint EP1 (index=02)
*/
void endpoint1_out_handler( void )
{
uchar status;
status = D12_ReadLastTransactionStatus(2); /* Clear interrupt flag */
UpdateUSBErrorFlags( 2, status );
}
/*
* Interrupt IN Handler... (EP1 TX request)
* Called when a packet has been transmitted to host via Interrupt Endpoint EP1 (index=03)
* A flag, USB_InterruptInTxReady, is set TRUE to signal to the application layer that
* the endpoint FIFO is ready to accept a new packet for transmission.
* The flag should also be set TRUE on device reset.
*/
void interrupt_in_handler( void )
{
uchar status;
status = D12_ReadLastTransactionStatus(3); /* Clear interrupt flag */
UpdateUSBErrorFlags( 3, status );
USB_InterruptInTxReady = TRUE; /* EP1 IN is ready to accept new TX data */
}
/*
* Bulk OUT Handler... (EP2 RX request)
* A packet (or two) has been received from host via Bulk Endpoint EP2 (index=04).
* Function read_Bulk_Out_RX_packet() is called to read packet(s) out of the D12 RX FIFO,
* storing the data in a RAM buffer, and to signal the application layer when the Bulk-Out
* transfer is complete. The first packet of a Bulk-Out transfer includes a packet
* header, formatted according to the USB Class protocol used (USBTMC/488, CDC, etc).
*
* The D12 RX FIFO is double-buffered, so there may be two incoming packets available,
* in which case read_Bulk_Out_RX_packet() needs to be called twice.
*/
void bulk_out_handler( void )
{
uchar status;
bool double_buf = FALSE;
status = D12_ReadLastTransactionStatus(D12_EP2_OUT); /* Clear interrupt flag */
UpdateUSBErrorFlags( 4, status );
status = D12_ReadEndpointStatus(D12_EP2_OUT);
if ( (status & 0x60) == 0x60 ) double_buf = TRUE;
read_Bulk_Out_RX_packet();
if ( double_buf ) read_Bulk_Out_RX_packet(); /* Both buffers have Rx data */
}
/*
* Bulk IN Handler... (EP2 TX request)
* Called when a packet has been transmitted to host via Bulk Endpoint EP2 (index=05).
* Signals when new data may be written into the D12 endpoint buffer for transmission.
* A flag, USB_BulkInTxReady, is set TRUE to signal to the application layer that
* the endpoint FIFO is ready to accept a new packet for transmission.
* The flag should also be set TRUE on device reset.
*
* Note on interface with application layer:
* A function, write_Bulk_In_TX_packet() (not shown), writes a packet into the D12 FIFO,
* taking data from a RAM buffer. The first packet of a Bulk-In transfer includes a
* packet header, formatted according to the USB Class protocol used (USBTMC, CDC, etc).
* After the first packet of a new transfer is transmitted, the application layer must
* wait for (USB_BulkInTxReady == TRUE) before sending subsequent packets.
*/
void bulk_in_handler( void )
{
uchar status;
debug_signal( BIT_2 );
status = D12_ReadLastTransactionStatus(5); /* Clear interrupt flag */
UpdateUSBErrorFlags( 5, status );
USB_BulkInTxReady = TRUE;
}
/*
* Update PDIUSBD12 Error status word array, following most recent bus transaction.
* A 16-bit word (array element) is allocated to each endpoint index.
* The 1st arg, ep_index, specifies the endpoint whose status is to be updated.
* The 2nd arg, status, is the byte returned from D12_ReadLastTransactionStatus(),
* in which bits b4..b1 make a 4 bit error code (value 0..15).
* This error code indicates a bit position in USB_ErrorFlags[ep_index] to set,
* except bit 0 is never set (code 0 => no error).
* Existing flags remain uncleared, so flags can accumulate on successive calls.
* USB_ErrorFlags[] elements are cleared on RESET, or manually using a debug tool.
*/
void UpdateUSBErrorFlags( uchar ep_index, uchar status )
{
uchar ErrCode = (status >> 1) & 0x0F;
ushort BitPosn = 1;
while ( ErrCode-- ) /* Find bit position to set (posn 1 => b0) */
{
BitPosn <<= 1;
}
if ( BitPosn != 1 ) USB_ErrorFlags[ep_index & 0x07] |= BitPosn;
}
/* end */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -