From ec537fd84d6ad3fd0dfa1b55efa2c2d554c1db48 Mon Sep 17 00:00:00 2001
From: Dean Camera <dean@fourwalledcubicle.com>
Date: Fri, 24 Dec 2010 17:05:41 +0000
Subject: [PATCH] Re-add in old Endpoint/Pipe workaround for unordered pipes -
 add new ORDERED_EP_CONFIG compile time option to override the workaround and
 use the previous behaviour that imposes correct Endpoint/Pipe ordering but
 produces smaller compiled code.

---
 LUFA/Drivers/USB/LowLevel/Endpoint.c      | 46 ++++++++++++++++++
 LUFA/Drivers/USB/LowLevel/Endpoint.h      |  3 +-
 LUFA/Drivers/USB/LowLevel/Pipe.c          | 58 +++++++++++++++++++++++
 LUFA/Drivers/USB/LowLevel/Pipe.h          |  3 +-
 LUFA/Drivers/USB/LowLevel/USBController.c |  1 +
 LUFA/ManPages/ChangeLog.txt               |  3 ++
 LUFA/ManPages/CompileTimeTokens.txt       |  5 ++
 LUFA/ManPages/FutureChanges.txt           |  1 +
 LUFA/ManPages/MigrationInformation.txt    |  6 ++-
 9 files changed, 123 insertions(+), 3 deletions(-)

diff --git a/LUFA/Drivers/USB/LowLevel/Endpoint.c b/LUFA/Drivers/USB/LowLevel/Endpoint.c
index a7b1e4b58..56c73fc48 100644
--- a/LUFA/Drivers/USB/LowLevel/Endpoint.c
+++ b/LUFA/Drivers/USB/LowLevel/Endpoint.c
@@ -43,6 +43,7 @@ bool Endpoint_ConfigureEndpoint_Prv(const uint8_t Number,
                                     const uint8_t UECFG0XData,
                                     const uint8_t UECFG1XData)
 {
+#if defined(CONTROL_ONLY_DEVICE) || defined(ORDERED_EP_CONFIG)
 	Endpoint_SelectEndpoint(Number);
 	Endpoint_EnableEndpoint();
 
@@ -51,6 +52,51 @@ bool Endpoint_ConfigureEndpoint_Prv(const uint8_t Number,
 	UECFG1X = UECFG1XData;
 
 	return Endpoint_IsConfigured();
+#else
+	uint8_t UECFG0XTemp[ENDPOINT_TOTAL_ENDPOINTS];
+	uint8_t UECFG1XTemp[ENDPOINT_TOTAL_ENDPOINTS];
+	uint8_t UEIENXTemp[ENDPOINT_TOTAL_ENDPOINTS];
+	
+	for (uint8_t EPNum = 0; EPNum < ENDPOINT_TOTAL_ENDPOINTS; EPNum++)
+	{
+		Endpoint_SelectEndpoint(EPNum);
+		UECFG0XTemp[EPNum] = UECFG0X;
+		UECFG1XTemp[EPNum] = UECFG1X;
+		UEIENXTemp[EPNum]  = UEIENX;
+	}
+	
+	UECFG0XTemp[Number] = UECFG0XData;
+	UECFG1XTemp[Number] = UECFG1XData;
+	UEIENXTemp[Number]  = 0;
+	
+	for (uint8_t EPNum = 1; EPNum < ENDPOINT_TOTAL_ENDPOINTS; EPNum++)
+	{
+		Endpoint_SelectEndpoint(EPNum);	
+		UEIENX  = 0;
+		UEINTX  = 0;
+		UECFG1X = 0;
+		Endpoint_DisableEndpoint();
+	}
+
+	for (uint8_t EPNum = 0; EPNum < ENDPOINT_TOTAL_ENDPOINTS; EPNum++)
+	{
+		if (!(UECFG1XTemp[EPNum] & (1 << ALLOC)))
+		  continue;
+		
+		Endpoint_SelectEndpoint(EPNum);		
+		Endpoint_EnableEndpoint();
+
+		UECFG0X = UECFG0XTemp[EPNum];
+		UECFG1X = UECFG1XTemp[EPNum];
+		UEIENX  = UEIENXTemp[EPNum];
+		
+		if (!(Endpoint_IsConfigured()))
+		  return false;
+	}
+	
+	Endpoint_SelectEndpoint(Number);
+	return true;
+#endif
 }
 
 void Endpoint_ClearEndpoints(void)
diff --git a/LUFA/Drivers/USB/LowLevel/Endpoint.h b/LUFA/Drivers/USB/LowLevel/Endpoint.h
index ea2e8cc53..c8f9cbfd5 100644
--- a/LUFA/Drivers/USB/LowLevel/Endpoint.h
+++ b/LUFA/Drivers/USB/LowLevel/Endpoint.h
@@ -273,7 +273,8 @@
 			 *                        More banks uses more USB DPRAM, but offers better performance. Isochronous type
 			 *                        endpoints <b>must</b> have at least two banks.
 			 *
-			 *  \note Endpoints <b>must</b> be configured in ascending order, or bank corruption will occur.
+			 *  \note When the ORDERED_EP_CONFIG compile time option is used, Endpoints <b>must</b> be configured in ascending
+			 *        order, or bank corruption will occur.
 			 *        \n\n
 			 *
 			 *  \note Certain models of USB AVR's endpoints may have different maximum packet sizes based on the endpoint's
diff --git a/LUFA/Drivers/USB/LowLevel/Pipe.c b/LUFA/Drivers/USB/LowLevel/Pipe.c
index 3656be20f..fc50060be 100644
--- a/LUFA/Drivers/USB/LowLevel/Pipe.c
+++ b/LUFA/Drivers/USB/LowLevel/Pipe.c
@@ -44,6 +44,7 @@ bool Pipe_ConfigurePipe(const uint8_t Number,
                         const uint16_t Size,
                         const uint8_t Banks)
 {
+#if defined(ORDERED_EP_CONFIG)
 	Pipe_SelectPipe(Number);
 	Pipe_EnablePipe();
 
@@ -55,6 +56,63 @@ bool Pipe_ConfigurePipe(const uint8_t Number,
 	Pipe_SetInfiniteINRequests();
 
 	return Pipe_IsConfigured();
+#else
+	uint8_t UPCFG0XTemp[PIPE_TOTAL_PIPES];
+	uint8_t UPCFG1XTemp[PIPE_TOTAL_PIPES];
+	uint8_t UPCFG2XTemp[PIPE_TOTAL_PIPES];
+	uint8_t UPCONXTemp[PIPE_TOTAL_PIPES];
+	uint8_t UPINRQXTemp[PIPE_TOTAL_PIPES];
+	uint8_t UPIENXTemp[PIPE_TOTAL_PIPES];
+	
+	for (uint8_t PNum = 0; PNum < PIPE_TOTAL_PIPES; PNum++)
+	{
+		Pipe_SelectPipe(PNum);
+		UPCFG0XTemp[PNum] = UPCFG0X;
+		UPCFG1XTemp[PNum] = UPCFG1X;
+		UPCFG2XTemp[PNum] = UPCFG2X;
+		UPCONXTemp[PNum]  = UPCONX;
+		UPINRQXTemp[PNum] = UPINRQX;
+		UPIENXTemp[PNum]  = UPIENX;
+	}
+	
+	UPCFG0XTemp[Number] = ((Type << EPTYPE0) | Token | ((EndpointNumber & PIPE_EPNUM_MASK) << PEPNUM0));
+	UPCFG1XTemp[Number] = ((1 << ALLOC) | Banks | Pipe_BytesToEPSizeMask(Size));
+	UPCFG2XTemp[Number] = 0;
+	UPCONXTemp[Number]  = (1 << INMODE);
+	UPINRQXTemp[Number] = 0;
+	UPIENXTemp[Number]  = 0;
+	
+	for (uint8_t PNum = 0; PNum < PIPE_TOTAL_PIPES; PNum++)
+	{
+		Pipe_SelectPipe(PNum);
+		UPIENX  = 0;
+		UPINTX  = 0;
+		UPCFG1X = 0;
+		Pipe_DisablePipe();
+	}
+
+	for (uint8_t PNum = 0; PNum < PIPE_TOTAL_PIPES; PNum++)
+	{
+		if (!(UPCFG1XTemp[PNum] & (1 << ALLOC)))
+		  continue;
+		
+		Pipe_SelectPipe(PNum);		
+		Pipe_EnablePipe();
+
+		UPCFG0X  = UPCFG0XTemp[PNum];
+		UPCFG1X  = UPCFG1XTemp[PNum];
+		UPCFG2X  = UPCFG2XTemp[PNum];
+		UPCONX  |= UPCONXTemp[PNum];
+		UPINRQX  = UPINRQXTemp[PNum];
+		UPIENX   = UPIENXTemp[PNum];
+
+		if (!(Pipe_IsConfigured()))
+		  return false;
+	}
+		
+	Pipe_SelectPipe(Number);	
+	return true;
+#endif
 }
 
 void Pipe_ClearPipes(void)
diff --git a/LUFA/Drivers/USB/LowLevel/Pipe.h b/LUFA/Drivers/USB/LowLevel/Pipe.h
index 0e877f623..f415189c2 100644
--- a/LUFA/Drivers/USB/LowLevel/Pipe.h
+++ b/LUFA/Drivers/USB/LowLevel/Pipe.h
@@ -861,7 +861,8 @@
 			 *                             uses more USB DPRAM, but offers better performance. Isochronous type pipes <b>must</b>
 			 *                             have at least two banks.
 			 *
-			 *  \note Endpoints <b>must</b> be configured in ascending order, or bank corruption will occur.
+			 *  \note When the ORDERED_EP_CONFIG compile time option is used, Pipes <b>must</b> be configured in ascending order,
+			 *        or bank corruption will occur.
 			 *        \n\n
 			 *
 			 *  \note Certain models of USB AVR's pipes may have different maximum packet sizes based on the pipe's
diff --git a/LUFA/Drivers/USB/LowLevel/USBController.c b/LUFA/Drivers/USB/LowLevel/USBController.c
index fc5725675..f778d66bf 100644
--- a/LUFA/Drivers/USB/LowLevel/USBController.c
+++ b/LUFA/Drivers/USB/LowLevel/USBController.c
@@ -152,6 +152,7 @@ void USB_ResetInterface(void)
 	{
 		#if defined(USB_CAN_BE_HOST)
 		UHWCON &= ~(1 << UIMOD);
+
 		USB_Init_Host();
 		#endif
 	}
diff --git a/LUFA/ManPages/ChangeLog.txt b/LUFA/ManPages/ChangeLog.txt
index 34e772d63..1bce5faba 100644
--- a/LUFA/ManPages/ChangeLog.txt
+++ b/LUFA/ManPages/ChangeLog.txt
@@ -10,6 +10,8 @@
   *  <b>New:</b>
   *  - Core:
   *   - Added new MIDIToneGenerator project
+  *   - Added new ORDERED_EP_CONFIG compile time option to restrict endpoint/pipe configuration to ascending order
+  *     in exchange for a smaller compiled program binary size
   *  - Library Applications:
   *   - Added new incomplete MIDIToneGenerator project
   *   - Added ability to write protect Mass Storage disk write operations from the host OS
@@ -17,6 +19,7 @@
   *
   *  <b>Changed:</b>
   *  - Core:
+  *   - Unordered Endpoint/Pipe configuration is now allowed once again via the previous reconfig workaround
   *   - Refactored Host mode Class Driver *_Host_ConfigurePipes() routines to be more space efficient when compiled
   *   - Added new *_ENUMERROR_PipeConfigurationFailed error codes for the *_Host_ConfigurePipes() routines
   *  - Library Applications:
diff --git a/LUFA/ManPages/CompileTimeTokens.txt b/LUFA/ManPages/CompileTimeTokens.txt
index 28b7cfc6b..b120617e0 100644
--- a/LUFA/ManPages/CompileTimeTokens.txt
+++ b/LUFA/ManPages/CompileTimeTokens.txt
@@ -77,6 +77,11 @@
  *  \section Sec_SummaryUSBTokens General USB Driver Related Tokens
  *  This section describes compile tokens which affect USB driver stack as a whole in the LUFA library.
  *
+ *  <b>ORDERED_EP_CONFIG</b> - ( \ref Group_EndpointManagement , \ref Group_PipeManagement )\n
+ *  The USB AVRs do not allow for Endpoints and Pipes to be configured out of order; they <i>must</i> be configured in an ascending order to
+ *  prevent data corruption issues. However, by default LUFA employs a workaround to allow for unordered Endpoint/Pipe initialisation. This compile
+ *  time token may be used to restrict the intialisation order to ascending indexes only in exchange for a smaller compiled binary size.
+ *
  *  <b>NO_STREAM_CALLBACKS</b> - ( \ref Group_EndpointPacketManagement , \ref Group_PipePacketManagement )\n
  *  Both the endpoint and the pipe driver code contains stream functions, allowing for arrays of data to be sent to or from the
  *  host easily via a single function call (rather than complex routines worrying about sending full packets, waiting for the endpoint/
diff --git a/LUFA/ManPages/FutureChanges.txt b/LUFA/ManPages/FutureChanges.txt
index 7ae15aa0b..bfa5a530f 100644
--- a/LUFA/ManPages/FutureChanges.txt
+++ b/LUFA/ManPages/FutureChanges.txt
@@ -20,6 +20,7 @@
   *      -# Re-add interrupt Pipe/Endpoint support
   *      -# Add HID report macros to make HID report editing easier
   *      -# Investigate dynamically created device descriptors
+  *      -# Check if ALL the workaround reg save/restore code in the unordered EP config is required
   *  - Documentation/Support
   *      -# Add detailed overviews of how each demo works
   *      -# Add board overviews
diff --git a/LUFA/ManPages/MigrationInformation.txt b/LUFA/ManPages/MigrationInformation.txt
index d12c3f9e9..3bbe5a195 100644
--- a/LUFA/ManPages/MigrationInformation.txt
+++ b/LUFA/ManPages/MigrationInformation.txt
@@ -11,7 +11,11 @@
  *  areas relevant to making older projects compatible with the API changes of each new release.
  *
  *  \section Sec_MigrationXXXXXX Migrating from 101122 to XXXXXX
- *  None yet.
+ *  <b>USB Core</b>
+ *    - By default, unordered Endpoint and Pipe configuration is now allowed once again, via the previous workaround of
+ *      reconfiguring all Endpoints/Pipes in order each time a new Endpoint/Pipe is created. To minimise the compiled program
+ *      size, the new ORDERED_EP_CONFIG compile time option may be defined in the project makefile to restrict the ordering
+ *      in exchange for a smaller compiled binary size.
  *
  *  \section Sec_Migration101122 Migrating from 100807 to 101122
  *  <b>USB Core</b>
-- 
GitLab