| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |     @file     dcd_lpc43xx.c | 
					
						
							|  |  |  |     @author   hathach (tinyusb.org) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @section LICENSE | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Software License Agreement (BSD License) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Copyright (c) 2013, hathach (tinyusb.org) | 
					
						
							|  |  |  |     All rights reserved. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Redistribution and use in source and binary forms, with or without | 
					
						
							|  |  |  |     modification, are permitted provided that the following conditions are met: | 
					
						
							|  |  |  |     1. Redistributions of source code must retain the above copyright | 
					
						
							|  |  |  |     notice, this list of conditions and the following disclaimer. | 
					
						
							|  |  |  |     2. Redistributions in binary form must reproduce the above copyright | 
					
						
							|  |  |  |     notice, this list of conditions and the following disclaimer in the | 
					
						
							|  |  |  |     documentation and/or other materials provided with the distribution. | 
					
						
							|  |  |  |     3. Neither the name of the copyright holders nor the | 
					
						
							|  |  |  |     names of its contributors may be used to endorse or promote products | 
					
						
							|  |  |  |     derived from this software without specific prior written permission. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY | 
					
						
							|  |  |  |     EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | 
					
						
							|  |  |  |     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 
					
						
							|  |  |  |     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY | 
					
						
							|  |  |  |     DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 
					
						
							|  |  |  |     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 
					
						
							|  |  |  |     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | 
					
						
							|  |  |  |     ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
					
						
							|  |  |  |     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 
					
						
							|  |  |  |     SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     This file is part of the tinyusb stack. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "tusb_option.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-23 15:25:45 +07:00
										 |  |  | #if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_LPC43XX
 | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  | //--------------------------------------------------------------------+
 | 
					
						
							|  |  |  | // INCLUDE
 | 
					
						
							|  |  |  | //--------------------------------------------------------------------+
 | 
					
						
							| 
									
										
										
										
											2018-03-12 22:45:35 +07:00
										 |  |  | #include "common/tusb_common.h"
 | 
					
						
							| 
									
										
										
										
											2018-03-02 18:43:00 +07:00
										 |  |  | #include "tusb_hal.h"
 | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | #include "osal/osal.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-28 13:44:39 +07:00
										 |  |  | #include "device/dcd.h"
 | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | #include "dcd_lpc43xx.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-09 23:04:53 +07:00
										 |  |  | #include "LPC43xx.h"
 | 
					
						
							|  |  |  | #include "lpc43xx_cgu.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | //--------------------------------------------------------------------+
 | 
					
						
							|  |  |  | // MACRO CONSTANT TYPEDEF
 | 
					
						
							|  |  |  | //--------------------------------------------------------------------+
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-06 14:20:45 +07:00
										 |  |  | //--------------------------------------------------------------------+
 | 
					
						
							|  |  |  | // INTERNAL OBJECT & FUNCTION DECLARATION
 | 
					
						
							|  |  |  | //--------------------------------------------------------------------+
 | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | typedef struct { | 
					
						
							| 
									
										
										
										
											2018-03-30 18:36:04 +07:00
										 |  |  |   dcd_qhd_t qhd[DCD_QHD_MAX] ATTR_ALIGNED(64); ///< Must be at 2K alignment
 | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  |   dcd_qtd_t qtd[DCD_QTD_MAX] ATTR_ALIGNED(32); | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | }dcd_data_t; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-24 23:40:28 +07:00
										 |  |  | extern ATTR_WEAK dcd_data_t dcd_data0; | 
					
						
							|  |  |  | extern ATTR_WEAK dcd_data_t dcd_data1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-14 14:08:48 +07:00
										 |  |  | #if (CFG_TUSB_RHPORT0_MODE & OPT_MODE_DEVICE)
 | 
					
						
							| 
									
										
										
										
											2018-04-10 14:31:11 +07:00
										 |  |  | CFG_TUSB_ATTR_USBRAM ATTR_ALIGNED(2048) STATIC_VAR dcd_data_t dcd_data0; | 
					
						
							| 
									
										
										
										
											2013-11-06 14:20:45 +07:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-14 14:08:48 +07:00
										 |  |  | #if (CFG_TUSB_RHPORT1_MODE & OPT_MODE_DEVICE)
 | 
					
						
							| 
									
										
										
										
											2018-04-10 14:31:11 +07:00
										 |  |  | CFG_TUSB_ATTR_USBRAM ATTR_ALIGNED(2048) STATIC_VAR dcd_data_t dcd_data1; | 
					
						
							| 
									
										
										
										
											2013-11-06 14:20:45 +07:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static LPC_USB0_Type * const LPC_USB[2] = { LPC_USB0, ((LPC_USB0_Type*) LPC_USB1_BASE) }; | 
					
						
							| 
									
										
										
										
											2014-04-24 23:40:28 +07:00
										 |  |  | static dcd_data_t* const dcd_data_ptr[2] = { &dcd_data0, &dcd_data1 }; | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  | //--------------------------------------------------------------------+
 | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  | // CONTROLLER API
 | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | //--------------------------------------------------------------------+
 | 
					
						
							| 
									
										
										
										
											2018-03-28 13:47:58 +07:00
										 |  |  | void dcd_connect(uint8_t rhport) | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  |   LPC_USB[rhport]->USBCMD_D |= BIT_(0); | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-28 13:47:58 +07:00
										 |  |  | void dcd_set_address(uint8_t rhport, uint8_t dev_addr) | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  |   LPC_USB[rhport]->DEVICEADDR = (dev_addr << 25) | BIT_(24); | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-28 13:47:58 +07:00
										 |  |  | void dcd_set_config(uint8_t rhport, uint8_t config_num) | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-29 14:19:56 +07:00
										 |  |  | /// follows LPC43xx User Manual 23.10.3
 | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  | static void bus_reset(uint8_t rhport) | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  |   LPC_USB0_Type* const lpc_usb = LPC_USB[rhport]; | 
					
						
							| 
									
										
										
										
											2013-10-29 14:19:56 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-30 12:20:00 +07:00
										 |  |  |   // The reset value for all endpoint types is the control endpoint. If one endpoint
 | 
					
						
							|  |  |  |   //direction is enabled and the paired endpoint of opposite direction is disabled, then the
 | 
					
						
							|  |  |  |   //endpoint type of the unused direction must bechanged from the control type to any other
 | 
					
						
							|  |  |  |   //type (e.g. bulk). Leaving an unconfigured endpoint control will cause undefined behavior
 | 
					
						
							|  |  |  |   //for the data PID tracking on the active endpoint.
 | 
					
						
							| 
									
										
										
										
											2013-11-06 14:20:45 +07:00
										 |  |  |   lpc_usb->ENDPTCTRL1 = lpc_usb->ENDPTCTRL2 = lpc_usb->ENDPTCTRL3 = | 
					
						
							| 
									
										
										
										
											2013-10-30 12:20:00 +07:00
										 |  |  |       (TUSB_XFER_BULK << 2) | (TUSB_XFER_BULK << 18); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-06 14:20:45 +07:00
										 |  |  |   // USB1 only has 3 non-control endpoints
 | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  |   if ( rhport == 0) | 
					
						
							| 
									
										
										
										
											2013-11-06 14:20:45 +07:00
										 |  |  |   { | 
					
						
							|  |  |  |     lpc_usb->ENDPTCTRL4 = lpc_usb->ENDPTCTRL5 = (TUSB_XFER_BULK << 2) | (TUSB_XFER_BULK << 18); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-29 14:19:56 +07:00
										 |  |  |   //------------- Clear All Registers -------------//
 | 
					
						
							| 
									
										
										
										
											2013-11-06 14:20:45 +07:00
										 |  |  |   lpc_usb->ENDPTNAK       = lpc_usb->ENDPTNAK; | 
					
						
							|  |  |  |   lpc_usb->ENDPTNAKEN     = 0; | 
					
						
							|  |  |  |   lpc_usb->USBSTS_D       = lpc_usb->USBSTS_D; | 
					
						
							|  |  |  |   lpc_usb->ENDPTSETUPSTAT = lpc_usb->ENDPTSETUPSTAT; | 
					
						
							|  |  |  |   lpc_usb->ENDPTCOMPLETE  = lpc_usb->ENDPTCOMPLETE; | 
					
						
							| 
									
										
										
										
											2013-10-29 14:19:56 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-06 14:20:45 +07:00
										 |  |  |   while (lpc_usb->ENDPTPRIME); | 
					
						
							|  |  |  |   lpc_usb->ENDPTFLUSH = 0xFFFFFFFF; | 
					
						
							|  |  |  |   while (lpc_usb->ENDPTFLUSH); | 
					
						
							| 
									
										
										
										
											2013-10-29 14:19:56 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // read reset bit in portsc
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   //------------- Queue Head & Queue TD -------------//
 | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  |   dcd_data_t* p_dcd = dcd_data_ptr[rhport]; | 
					
						
							| 
									
										
										
										
											2013-11-06 14:20:45 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-23 12:19:32 +07:00
										 |  |  |   tu_memclr(p_dcd, sizeof(dcd_data_t)); | 
					
						
							| 
									
										
										
										
											2013-10-29 14:19:56 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   //------------- Set up Control Endpoints (0 OUT, 1 IN) -------------//
 | 
					
						
							| 
									
										
										
										
											2013-11-06 14:20:45 +07:00
										 |  |  | 	p_dcd->qhd[0].zero_length_termination = p_dcd->qhd[1].zero_length_termination = 1; | 
					
						
							| 
									
										
										
										
											2018-04-12 13:23:52 +07:00
										 |  |  | 	p_dcd->qhd[0].max_package_size = p_dcd->qhd[1].max_package_size = CFG_TUD_ENDOINT0_SIZE; | 
					
						
							| 
									
										
										
										
											2013-11-06 14:20:45 +07:00
										 |  |  | 	p_dcd->qhd[0].qtd_overlay.next = p_dcd->qhd[1].qtd_overlay.next = QTD_NEXT_INVALID; | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-06 14:20:45 +07:00
										 |  |  | 	p_dcd->qhd[0].int_on_setup = 1; // OUT only
 | 
					
						
							| 
									
										
										
										
											2013-11-15 13:26:12 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-28 13:47:58 +07:00
										 |  |  | bool dcd_init(uint8_t rhport) | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  |   LPC_USB0_Type* const lpc_usb = LPC_USB[rhport]; | 
					
						
							|  |  |  |   dcd_data_t* p_dcd = dcd_data_ptr[rhport]; | 
					
						
							| 
									
										
										
										
											2013-11-06 14:20:45 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-23 12:19:32 +07:00
										 |  |  |   tu_memclr(p_dcd, sizeof(dcd_data_t)); | 
					
						
							| 
									
										
										
										
											2013-11-06 14:20:45 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   lpc_usb->ENDPOINTLISTADDR = (uint32_t) p_dcd->qhd; // Endpoint List Address has to be 2K alignment
 | 
					
						
							| 
									
										
										
										
											2013-11-06 14:53:18 +07:00
										 |  |  |   lpc_usb->USBSTS_D  = lpc_usb->USBSTS_D; | 
					
						
							| 
									
										
										
										
											2018-03-08 14:55:02 +07:00
										 |  |  |   lpc_usb->USBINTR_D = INT_MASK_USB | INT_MASK_ERROR | INT_MASK_PORT_CHANGE | INT_MASK_RESET | INT_MASK_SUSPEND | INT_MASK_SOF; | 
					
						
							| 
									
										
										
										
											2013-11-15 13:26:12 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   lpc_usb->USBCMD_D &= ~0x00FF0000; // Interrupt Threshold Interval = 0
 | 
					
						
							|  |  |  |   lpc_usb->USBCMD_D |= BIT_(0); // connect
 | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-13 16:30:53 +07:00
										 |  |  |   // enable interrupt
 | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  |   NVIC_EnableIRQ(rhport ? USB1_IRQn : USB0_IRQn); | 
					
						
							| 
									
										
										
										
											2018-03-13 16:30:53 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-02 22:46:36 +07:00
										 |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //--------------------------------------------------------------------+
 | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  | // PIPE HELPER
 | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | //--------------------------------------------------------------------+
 | 
					
						
							| 
									
										
										
										
											2014-03-23 17:33:58 +07:00
										 |  |  | #if 0
 | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  | static inline uint8_t edpt_pos2phy(uint8_t pos) | 
					
						
							|  |  |  | { // 0-5 --> OUT, 16-21 IN
 | 
					
						
							|  |  |  |   return (pos < DCD_QHD_MAX/2) ? (2*pos) : (2*(pos-16)+1); | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-03-23 17:33:58 +07:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  | static inline uint8_t edpt_phy2pos(uint8_t physical_endpoint) | 
					
						
							| 
									
										
										
										
											2013-10-29 15:09:16 +07:00
										 |  |  | { | 
					
						
							|  |  |  |   return physical_endpoint/2 + ( (physical_endpoint%2) ? 16 : 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  | static inline uint8_t edpt_addr2phy(uint8_t endpoint_addr) | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-11 20:20:59 +07:00
										 |  |  |   return 2*(endpoint_addr & 0x0F) + ((endpoint_addr & TUSB_DIR_IN_MASK) ? 1 : 0); | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-11 15:20:27 +07:00
										 |  |  | static inline uint8_t edpt_phy2addr(uint8_t ep_idx) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-11 20:20:59 +07:00
										 |  |  |   return (ep_idx/2) | ( ep_idx & 0x01 ? TUSB_DIR_IN_MASK : 0 ); | 
					
						
							| 
									
										
										
										
											2018-03-11 15:20:27 +07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  | static inline uint8_t edpt_phy2log(uint8_t physical_endpoint) | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  |   return physical_endpoint/2; | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void qtd_init(dcd_qtd_t* p_qtd, void * data_ptr, uint16_t total_bytes) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-10-23 12:19:32 +07:00
										 |  |  |   tu_memclr(p_qtd, sizeof(dcd_qtd_t)); | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  |   p_qtd->used        = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   p_qtd->next        = QTD_NEXT_INVALID; | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  |   p_qtd->active      = 1; | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  |   p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes; | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (data_ptr != NULL) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     p_qtd->buffer[0]   = (uint32_t) data_ptr; | 
					
						
							|  |  |  |     for(uint8_t i=1; i<5; i++) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2018-08-23 20:09:28 +07:00
										 |  |  |       p_qtd->buffer[i] |= tu_align4k( p_qtd->buffer[i-1] ) + 4096; | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  | // retval 0: invalid
 | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  | static inline uint8_t qtd_find_free(uint8_t rhport) | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-23 11:53:49 +07:00
										 |  |  |   // QTD0 is reserved for control transfer
 | 
					
						
							|  |  |  |   for(uint8_t i=1; i<DCD_QTD_MAX; i++) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  |     if ( dcd_data_ptr[rhport]->qtd[i].used == 0) return i; | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //--------------------------------------------------------------------+
 | 
					
						
							|  |  |  | // CONTROL PIPE API
 | 
					
						
							|  |  |  | //--------------------------------------------------------------------+
 | 
					
						
							| 
									
										
										
										
											2013-10-30 12:52:25 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  | // control transfer does not need to use qtd find function
 | 
					
						
							| 
									
										
										
										
											2014-04-21 21:55:17 +07:00
										 |  |  | // follows UM 24.10.8.1.1 Setup packet handling using setup lockout mechanism
 | 
					
						
							| 
									
										
										
										
											2018-08-23 20:54:51 +07:00
										 |  |  | bool dcd_control_xfer(uint8_t rhport, uint8_t dir, uint8_t * p_buffer, uint16_t length) | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  |   LPC_USB0_Type* const lpc_usb = LPC_USB[rhport]; | 
					
						
							|  |  |  |   dcd_data_t* const p_dcd      = dcd_data_ptr[rhport]; | 
					
						
							| 
									
										
										
										
											2013-12-09 11:49:34 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 15:32:35 +07:00
										 |  |  |   uint8_t const ep_phy = (dir == TUSB_DIR_IN) ? 1 : 0; | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 15:32:35 +07:00
										 |  |  |   dcd_qhd_t* qhd = &p_dcd->qhd[ep_phy]; | 
					
						
							| 
									
										
										
										
											2014-05-13 10:37:28 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 15:32:35 +07:00
										 |  |  |   // wait until ENDPTSETUPSTAT before priming data/status in response TODO add time out
 | 
					
						
							|  |  |  |   while(lpc_usb->ENDPTSETUPSTAT & BIT_(0)) {} | 
					
						
							| 
									
										
										
										
											2013-11-06 14:20:45 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-13 18:10:23 +07:00
										 |  |  |   TU_VERIFY( !qhd->qtd_overlay.active ); | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 15:32:35 +07:00
										 |  |  |   dcd_qtd_t* qtd = &p_dcd->qtd[0]; | 
					
						
							|  |  |  |   qtd_init(qtd, p_buffer, length); | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 15:32:35 +07:00
										 |  |  |   // skip xfer complete for Status
 | 
					
						
							|  |  |  |   qtd->int_on_complete = (length > 0 ? 1 : 0); | 
					
						
							| 
									
										
										
										
											2013-12-09 11:49:34 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 15:32:35 +07:00
										 |  |  |   qhd->qtd_overlay.next = (uint32_t) qtd; | 
					
						
							| 
									
										
										
										
											2013-12-09 11:49:34 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 15:32:35 +07:00
										 |  |  |   lpc_usb->ENDPTPRIME = BIT_(edpt_phy2pos(ep_phy)); | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-03 12:30:38 +07:00
										 |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //--------------------------------------------------------------------+
 | 
					
						
							|  |  |  | // BULK/INTERRUPT/ISOCHRONOUS PIPE API
 | 
					
						
							|  |  |  | //--------------------------------------------------------------------+
 | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  | static inline volatile uint32_t * get_reg_control_addr(uint8_t rhport, uint8_t physical_endpoint) | 
					
						
							| 
									
										
										
										
											2013-11-06 14:20:45 +07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  |  return &(LPC_USB[rhport]->ENDPTCTRL0) + edpt_phy2log(physical_endpoint); | 
					
						
							| 
									
										
										
										
											2013-11-06 14:20:45 +07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-28 13:47:58 +07:00
										 |  |  | void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  |   uint8_t ep_idx    = edpt_addr2phy(ep_addr); | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  |   volatile uint32_t * reg_control = get_reg_control_addr(rhport, ep_idx); | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 16:08:42 +07:00
										 |  |  |   if ( ep_addr == 0) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // Stall both Control IN and OUT
 | 
					
						
							|  |  |  |     (*reg_control) |= ( (ENDPTCTRL_MASK_STALL << 16) || (ENDPTCTRL_MASK_STALL << 0) ); | 
					
						
							|  |  |  |   }else | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     (*reg_control) |= ENDPTCTRL_MASK_STALL << (ep_idx & 0x01 ? 16 : 0); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-28 13:47:58 +07:00
										 |  |  | void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) | 
					
						
							| 
									
										
										
										
											2013-11-01 14:44:14 +07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  |   volatile uint32_t * reg_control = get_reg_control_addr(rhport, edpt_addr2phy(ep_addr)); | 
					
						
							| 
									
										
										
										
											2013-11-01 14:44:14 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 22:00:39 +07:00
										 |  |  |   // data toggle also need to be reset
 | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  |   (*reg_control) |= ENDPTCTRL_MASK_TOGGLE_RESET << ((ep_addr & TUSB_DIR_IN_MASK) ? 16 : 0); | 
					
						
							|  |  |  |   (*reg_control) &= ~(ENDPTCTRL_MASK_STALL << ((ep_addr & TUSB_DIR_IN_MASK) ? 16 : 0)); | 
					
						
							| 
									
										
										
										
											2013-11-01 14:44:14 +07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-28 13:47:58 +07:00
										 |  |  | bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | { | 
					
						
							|  |  |  |   // TODO USB1 only has 4 non-control enpoint (USB0 has 5)
 | 
					
						
							| 
									
										
										
										
											2018-03-06 16:50:50 +07:00
										 |  |  |   // TODO not support ISO yet
 | 
					
						
							| 
									
										
										
										
											2018-08-13 18:10:23 +07:00
										 |  |  |   TU_VERIFY ( p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS); | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-11 20:20:59 +07:00
										 |  |  |   tusb_dir_t dir = (p_endpoint_desc->bEndpointAddress & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT; | 
					
						
							| 
									
										
										
										
											2013-10-30 14:13:06 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  |   //------------- Prepare Queue Head -------------//
 | 
					
						
							| 
									
										
										
										
											2013-11-06 14:20:45 +07:00
										 |  |  |   uint8_t ep_idx    = edpt_addr2phy(p_endpoint_desc->bEndpointAddress); | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  |   dcd_qhd_t * p_qhd = &dcd_data_ptr[rhport]->qhd[ep_idx]; | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-23 12:19:32 +07:00
										 |  |  |   tu_memclr(p_qhd, sizeof(dcd_qhd_t)); | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   p_qhd->zero_length_termination = 1; | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  |   p_qhd->max_package_size        = p_endpoint_desc->wMaxPacketSize.size; | 
					
						
							|  |  |  |   p_qhd->qtd_overlay.next        = QTD_NEXT_INVALID; | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-06 14:20:45 +07:00
										 |  |  |   //------------- Endpoint Control Register -------------//
 | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  |   volatile uint32_t * reg_control = get_reg_control_addr(rhport, ep_idx); | 
					
						
							| 
									
										
										
										
											2013-11-06 14:20:45 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-06 17:03:19 +07:00
										 |  |  |   // endpoint must not be already enabled
 | 
					
						
							| 
									
										
										
										
											2018-08-13 18:10:23 +07:00
										 |  |  |   TU_VERIFY( !( (*reg_control) &  (ENDPTCTRL_MASK_ENABLE << (dir ? 16 : 0)) ) ); | 
					
						
							| 
									
										
										
										
											2018-03-06 17:03:19 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-30 14:13:06 +07:00
										 |  |  |   (*reg_control) |= ((p_endpoint_desc->bmAttributes.xfer << 2) | ENDPTCTRL_MASK_ENABLE | ENDPTCTRL_MASK_TOGGLE_RESET) << (dir ? 16 : 0); | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-06 17:03:19 +07:00
										 |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2013-10-29 14:19:56 +07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-28 13:47:58 +07:00
										 |  |  | bool dcd_edpt_busy(uint8_t rhport, uint8_t ep_addr) | 
					
						
							| 
									
										
										
										
											2013-10-29 15:09:16 +07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  |   uint8_t ep_idx    = edpt_addr2phy(ep_addr); | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  |   dcd_qhd_t const * p_qhd = &dcd_data_ptr[rhport]->qhd[ep_idx]; | 
					
						
							| 
									
										
										
										
											2013-10-29 15:09:16 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-24 23:40:28 +07:00
										 |  |  |   return p_qhd->list_qtd_idx[0] != 0; // qtd list is not empty
 | 
					
						
							|  |  |  | //  return !p_qhd->qtd_overlay.halted && p_qhd->qtd_overlay.active;
 | 
					
						
							| 
									
										
										
										
											2013-10-29 15:09:16 +07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  | // add only, controller virtually cannot know
 | 
					
						
							| 
									
										
										
										
											2018-03-28 13:47:58 +07:00
										 |  |  | // TODO remove and merge to dcd_edpt_xfer
 | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  | static bool pipe_add_xfer(uint8_t rhport, uint8_t ed_idx, void * buffer, uint16_t total_bytes, bool int_on_complete) | 
					
						
							| 
									
										
										
										
											2013-10-29 14:19:56 +07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  |   uint8_t qtd_idx  = qtd_find_free(rhport); | 
					
						
							| 
									
										
										
										
											2018-03-12 22:37:12 +07:00
										 |  |  |   TU_ASSERT(qtd_idx != 0); | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  |   dcd_data_t* p_dcd = dcd_data_ptr[rhport]; | 
					
						
							| 
									
										
										
										
											2018-03-11 15:20:27 +07:00
										 |  |  |   dcd_qhd_t * p_qhd = &p_dcd->qhd[ed_idx]; | 
					
						
							| 
									
										
										
										
											2013-11-06 14:20:45 +07:00
										 |  |  |   dcd_qtd_t * p_qtd = &p_dcd->qtd[qtd_idx]; | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   //------------- Find free slot in qhd's array list -------------//
 | 
					
						
							|  |  |  |   uint8_t free_slot; | 
					
						
							|  |  |  |   for(free_slot=0; free_slot < DCD_QTD_PER_QHD_MAX; free_slot++) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     if ( p_qhd->list_qtd_idx[free_slot] == 0 )  break; // found free slot
 | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-03-12 22:37:12 +07:00
										 |  |  |   TU_ASSERT(free_slot < DCD_QTD_PER_QHD_MAX); | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   p_qhd->list_qtd_idx[free_slot] = qtd_idx; // add new qtd to qhd's array list
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-29 14:19:56 +07:00
										 |  |  |   //------------- Prepare qtd -------------//
 | 
					
						
							|  |  |  |   qtd_init(p_qtd, buffer, total_bytes); | 
					
						
							|  |  |  |   p_qtd->int_on_complete = int_on_complete; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-06 14:20:45 +07:00
										 |  |  |   if ( free_slot > 0 ) p_dcd->qtd[ p_qhd->list_qtd_idx[free_slot-1] ].next = (uint32_t) p_qtd; | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-12 22:37:12 +07:00
										 |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-28 13:47:58 +07:00
										 |  |  | bool  dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  |   uint8_t ep_idx = edpt_addr2phy(ep_addr); | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-13 18:10:23 +07:00
										 |  |  |   TU_VERIFY ( pipe_add_xfer(rhport, ep_idx, buffer, total_bytes, true) ); | 
					
						
							| 
									
										
										
										
											2018-03-11 15:20:27 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  |   dcd_qhd_t* p_qhd = &dcd_data_ptr[rhport]->qhd[ ep_idx ]; | 
					
						
							|  |  |  |   dcd_qtd_t* p_qtd = &dcd_data_ptr[rhport]->qtd[ p_qhd->list_qtd_idx[0] ]; | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  |   p_qhd->qtd_overlay.next = (uint32_t) p_qtd; // attach head QTD to QHD start transferring
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  | 	LPC_USB[rhport]->ENDPTPRIME = BIT_( edpt_phy2pos(ep_idx) ) ; | 
					
						
							| 
									
										
										
										
											2013-10-29 14:19:56 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-12 22:37:12 +07:00
										 |  |  | 	return true; | 
					
						
							| 
									
										
										
										
											2013-10-29 14:19:56 +07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //------------- Device Controller Driver's Interrupt Handler -------------//
 | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  | void xfer_complete_isr(uint8_t rhport, uint32_t reg_complete) | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  | { | 
					
						
							|  |  |  |   for(uint8_t ep_idx = 2; ep_idx < DCD_QHD_MAX; ep_idx++) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     if ( BIT_TEST_(reg_complete, edpt_phy2pos(ep_idx)) ) | 
					
						
							|  |  |  |     { // 23.10.12.3 Failed QTD also get ENDPTCOMPLETE set
 | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  |       dcd_qhd_t * p_qhd = &dcd_data_ptr[rhport]->qhd[ep_idx]; | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       // retire all QTDs in array list, up to 1st still-active QTD
 | 
					
						
							|  |  |  |       while( p_qhd->list_qtd_idx[0] != 0 ) | 
					
						
							|  |  |  |       { | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  |         dcd_qtd_t * p_qtd = &dcd_data_ptr[rhport]->qtd[ p_qhd->list_qtd_idx[0] ]; | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (p_qtd->active)  break; // stop immediately if found still-active QTD and shift array list
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         //------------- Free QTD and shift array list -------------//
 | 
					
						
							|  |  |  |         p_qtd->used = 0; // free QTD
 | 
					
						
							| 
									
										
										
										
											2014-04-25 15:16:52 +07:00
										 |  |  |         memmove( (void*) p_qhd->list_qtd_idx, (void*) (p_qhd->list_qtd_idx+1), DCD_QTD_PER_QHD_MAX-1); | 
					
						
							| 
									
										
										
										
											2013-11-01 22:00:39 +07:00
										 |  |  |         p_qhd->list_qtd_idx[DCD_QTD_PER_QHD_MAX-1]=0; | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (p_qtd->int_on_complete) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2018-10-24 00:44:26 +07:00
										 |  |  |           uint8_t result = p_qtd->halted  ? DCD_XFER_STALLED : | 
					
						
							|  |  |  |                            ( p_qtd->xact_err ||p_qtd->buffer_err ) ? DCD_XFER_FAILED : DCD_XFER_SUCCESS; | 
					
						
							| 
									
										
										
										
											2018-03-11 15:20:27 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-17 02:17:40 +07:00
										 |  |  |           uint8_t ep_addr = edpt_phy2addr(ep_idx); | 
					
						
							| 
									
										
										
										
											2018-10-24 00:44:26 +07:00
										 |  |  |           dcd_event_xfer_complete(rhport, ep_addr, p_qtd->expected_bytes - p_qtd->total_bytes, result, true); // only number of bytes in the IOC qtd
 | 
					
						
							| 
									
										
										
										
											2013-11-01 12:11:26 +07:00
										 |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  | void hal_dcd_isr(uint8_t rhport) | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  |   LPC_USB0_Type* const lpc_usb = LPC_USB[rhport]; | 
					
						
							| 
									
										
										
										
											2013-11-06 14:20:45 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-23 17:33:58 +07:00
										 |  |  |   uint32_t const int_enable = lpc_usb->USBINTR_D; | 
					
						
							|  |  |  |   uint32_t const int_status = lpc_usb->USBSTS_D & int_enable; | 
					
						
							|  |  |  |   lpc_usb->USBSTS_D = int_status; // Acknowledge handled interrupt
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (int_status == 0) return;// disabled interrupt sources
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-23 16:07:48 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-23 17:33:58 +07:00
										 |  |  |   if (int_status & INT_MASK_RESET) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  |     bus_reset(rhport); | 
					
						
							| 
									
										
										
										
											2018-10-23 16:07:48 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-24 00:44:26 +07:00
										 |  |  |     dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_BUS_RESET }; | 
					
						
							| 
									
										
										
										
											2018-10-23 16:07:48 +07:00
										 |  |  |     dcd_event_handler(&event, true); | 
					
						
							| 
									
										
										
										
											2014-03-23 17:33:58 +07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (int_status & INT_MASK_SUSPEND) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     if (lpc_usb->PORTSC1_D & PORTSC_SUSPEND_MASK) | 
					
						
							|  |  |  |     { // Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration.
 | 
					
						
							|  |  |  |       if ((lpc_usb->DEVICEADDR >> 25) & 0x0f) | 
					
						
							|  |  |  |       { | 
					
						
							| 
									
										
										
										
											2018-10-24 00:44:26 +07:00
										 |  |  |         dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SUSPENDED }; | 
					
						
							| 
									
										
										
										
											2018-10-23 16:07:48 +07:00
										 |  |  |         dcd_event_handler(&event, true); | 
					
						
							| 
									
										
										
										
											2014-03-23 17:33:58 +07:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // TODO disconnection does not generate interrupt !!!!!!
 | 
					
						
							| 
									
										
										
										
											2013-11-22 16:10:05 +07:00
										 |  |  | //	if (int_status & INT_MASK_PORT_CHANGE)
 | 
					
						
							| 
									
										
										
										
											2013-11-22 15:16:24 +07:00
										 |  |  | //	{
 | 
					
						
							| 
									
										
										
										
											2013-11-22 16:10:05 +07:00
										 |  |  | //	  if ( !(lpc_usb->PORTSC1_D & PORTSC_CURRENT_CONNECT_STATUS_MASK) )
 | 
					
						
							| 
									
										
										
										
											2013-11-22 15:16:24 +07:00
										 |  |  | //	  {
 | 
					
						
							| 
									
										
										
										
											2018-10-24 00:44:26 +07:00
										 |  |  | //      dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_UNPLUGGED };
 | 
					
						
							| 
									
										
										
										
											2018-10-23 16:07:48 +07:00
										 |  |  | //      dcd_event_handler(&event, true);
 | 
					
						
							| 
									
										
										
										
											2013-11-22 15:16:24 +07:00
										 |  |  | //	  }
 | 
					
						
							|  |  |  | //	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-23 17:33:58 +07:00
										 |  |  |   if (int_status & INT_MASK_USB) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     uint32_t const edpt_complete = lpc_usb->ENDPTCOMPLETE; | 
					
						
							|  |  |  |     lpc_usb->ENDPTCOMPLETE = edpt_complete; // acknowledge
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  |     dcd_data_t* const p_dcd = dcd_data_ptr[rhport]; | 
					
						
							| 
									
										
										
										
											2014-03-23 17:33:58 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     //------------- Set up Received -------------//
 | 
					
						
							|  |  |  |     if (lpc_usb->ENDPTSETUPSTAT) | 
					
						
							| 
									
										
										
										
											2018-03-21 15:32:35 +07:00
										 |  |  |     { | 
					
						
							|  |  |  |       // 23.10.10.2 Operational model for setup transfers
 | 
					
						
							| 
									
										
										
										
											2014-03-23 17:33:58 +07:00
										 |  |  |       lpc_usb->ENDPTSETUPSTAT = lpc_usb->ENDPTSETUPSTAT;// acknowledge
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-24 00:44:26 +07:00
										 |  |  |       dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SETUP_RECEIVED }; | 
					
						
							| 
									
										
										
										
											2018-10-23 16:07:48 +07:00
										 |  |  |       event.setup_received = p_dcd->qhd[0].setup_request; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       dcd_event_handler(&event, true); | 
					
						
							| 
									
										
										
										
											2014-03-23 17:33:58 +07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-03-30 18:36:04 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-23 17:33:58 +07:00
										 |  |  |     //------------- Control Request Completed -------------//
 | 
					
						
							| 
									
										
										
										
											2018-03-21 15:32:35 +07:00
										 |  |  |     else if ( edpt_complete & ( BIT_(0) | BIT_(16)) ) | 
					
						
							| 
									
										
										
										
											2014-04-04 12:22:33 +07:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2018-03-30 18:36:04 +07:00
										 |  |  |       // determine Control OUT or IN
 | 
					
						
							|  |  |  |       uint8_t ep_idx =  BIT_TEST_(edpt_complete, 0) ? 0 : 1; | 
					
						
							| 
									
										
										
										
											2014-04-04 12:22:33 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-30 18:36:04 +07:00
										 |  |  |       // TODO use the actual QTD instead of the qhd's overlay to get expected bytes for actual byte xferred
 | 
					
						
							|  |  |  |       dcd_qtd_t* const p_qtd =  (dcd_qtd_t*) p_dcd->qhd[ep_idx].qtd_addr; | 
					
						
							| 
									
										
										
										
											2018-03-21 16:08:42 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-30 18:36:04 +07:00
										 |  |  |       if ( p_qtd->int_on_complete ) | 
					
						
							|  |  |  |       { | 
					
						
							| 
									
										
										
										
											2018-10-24 00:44:26 +07:00
										 |  |  |         uint8_t result = p_qtd->halted  ? DCD_XFER_STALLED : | 
					
						
							|  |  |  |                         ( p_qtd->xact_err ||p_qtd->buffer_err ) ? DCD_XFER_FAILED : DCD_XFER_SUCCESS; | 
					
						
							| 
									
										
										
										
											2018-03-30 18:36:04 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-24 00:44:26 +07:00
										 |  |  |         dcd_event_xfer_complete(rhport, 0, p_qtd->expected_bytes - p_qtd->total_bytes, result, true); | 
					
						
							| 
									
										
										
										
											2014-04-04 12:22:33 +07:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2014-03-23 17:33:58 +07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-23 17:33:58 +07:00
										 |  |  |     //------------- Transfer Complete -------------//
 | 
					
						
							| 
									
										
										
										
											2018-03-21 15:32:35 +07:00
										 |  |  |     if ( edpt_complete & ~(BIT_(0) | BIT_(16)) ) | 
					
						
							| 
									
										
										
										
											2014-03-23 17:33:58 +07:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2018-03-23 12:17:47 +07:00
										 |  |  |       xfer_complete_isr(rhport, edpt_complete); | 
					
						
							| 
									
										
										
										
											2014-03-23 17:33:58 +07:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-08 14:38:06 +07:00
										 |  |  |   if (int_status & INT_MASK_SOF) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2018-10-24 00:44:26 +07:00
										 |  |  |     dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SOF }; | 
					
						
							| 
									
										
										
										
											2018-10-23 16:07:48 +07:00
										 |  |  |     dcd_event_handler(&event, true); | 
					
						
							| 
									
										
										
										
											2018-03-08 14:38:06 +07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-23 17:33:58 +07:00
										 |  |  |   if (int_status & INT_MASK_NAK) {} | 
					
						
							| 
									
										
										
										
											2018-03-28 14:49:00 +07:00
										 |  |  |   if (int_status & INT_MASK_ERROR) TU_ASSERT(false, ); | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-10-29 14:19:56 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  | //--------------------------------------------------------------------+
 | 
					
						
							|  |  |  | // HELPER
 | 
					
						
							|  |  |  | //--------------------------------------------------------------------+
 | 
					
						
							| 
									
										
										
										
											2013-10-29 11:27:25 +07:00
										 |  |  | #endif
 |