⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usbisr.c

📁 PDIUSBD12的嵌入式软件
💻 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 + -