From eb410869474e14ec5762a96b930bc200409b6915 Mon Sep 17 00:00:00 2001
From: Dean Camera <dean@fourwalledcubicle.com>
Date: Fri, 31 Jul 2009 03:22:08 +0000
Subject: [PATCH] Fix demos based on the device mode HID class driver, as well
 as the driver itself. Changed HID device class driver to require the user to
 give a buffer and size to hold the previously generated report, for
 comparison purposes, and altered the prototype of the
 CALLBACK_HID_Device_CreateHIDReport() function so that reports can be sent to
 the host even if there are no apparent changes (useful for relative movements
 in mice, etc.).

---
 .../ClassDriver/GenericHID/GenericHID.c       | 15 +++++++--
 .../ClassDriver/GenericHID/GenericHID.h       |  8 ++---
 Demos/Device/ClassDriver/Joystick/Joystick.c  | 15 +++++++--
 Demos/Device/ClassDriver/Joystick/Joystick.h  |  8 ++---
 Demos/Device/ClassDriver/Keyboard/Keyboard.c  | 17 +++++++---
 Demos/Device/ClassDriver/Keyboard/Keyboard.h  |  8 ++---
 .../ClassDriver/KeyboardMouse/KeyboardMouse.c | 26 ++++++++++++---
 .../ClassDriver/KeyboardMouse/KeyboardMouse.h |  8 ++---
 Demos/Device/ClassDriver/Mouse/Mouse.c        | 15 +++++++--
 Demos/Device/ClassDriver/Mouse/Mouse.h        |  8 ++---
 LUFA/Drivers/USB/Class/Device/HID.c           | 18 +++++------
 LUFA/Drivers/USB/Class/Device/HID.h           | 32 +++++++++----------
 Projects/Magstripe/Magstripe.c                | 23 +++++++++----
 Projects/Magstripe/Magstripe.h                |  8 ++---
 14 files changed, 135 insertions(+), 74 deletions(-)

diff --git a/Demos/Device/ClassDriver/GenericHID/GenericHID.c b/Demos/Device/ClassDriver/GenericHID/GenericHID.c
index 4315723f4..9db30cebf 100644
--- a/Demos/Device/ClassDriver/GenericHID/GenericHID.c
+++ b/Demos/Device/ClassDriver/GenericHID/GenericHID.c
@@ -36,6 +36,9 @@
 
 #include "GenericHID.h"
 
+/** Buffer to hold the previously generated HID report, for comparison purposes inside the HID class driver. */
+uint8_t PrevHIDReportBuffer[GENERIC_REPORT_SIZE];
+
 /** LUFA HID Class driver interface configuration and state information. This structure is
  *  passed to all HID Class driver functions, so that multiple instances of the same class
  *  within a device can be differentiated from one another.
@@ -48,6 +51,9 @@ USB_ClassInfo_HID_Device_t Generic_HID_Interface =
 
 				.ReportINEndpointNumber  = GENERIC_IN_EPNUM,
 				.ReportINEndpointSize    = GENERIC_EPSIZE,
+				
+				.PrevReportINBuffer      = PrevHIDReportBuffer,
+				.PrevReportINBufferSize  = sizeof(PrevHIDReportBuffer),
 			},
 	};
 
@@ -126,14 +132,17 @@ ISR(TIMER0_COMPA_vect, ISR_BLOCK)
  *  \param[in] HIDInterfaceInfo  Pointer to the HID class interface configuration structure being referenced
  *  \param[in,out] ReportID  Report ID requested by the host if non-zero, otherwise callback should set to the generated report ID
  *  \param[out] ReportData  Pointer to a buffer where the created report should be stored
+ *  \param[out] ReportSize  Number of bytes written in the report (or zero if no report is to be sent
  *
- *  \return Number of bytes written in the report (or zero if no report is to be sent
+ *  \return Boolean true to force the sending of the report, false to let the library determine if it needs to be sent
  */
-uint16_t CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, uint8_t* const ReportID, void* ReportData)
+bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, uint8_t* const ReportID,
+                                         void* ReportData, uint16_t* ReportSize)
 {
 	// Create generic HID report here
 	
-	return 0;
+	*ReportSize = 0;
+	return true;
 }
 
 /** HID class driver callback function for the processing of HID reports from the host.
diff --git a/Demos/Device/ClassDriver/GenericHID/GenericHID.h b/Demos/Device/ClassDriver/GenericHID/GenericHID.h
index 6d5de7177..50a92ec1e 100644
--- a/Demos/Device/ClassDriver/GenericHID/GenericHID.h
+++ b/Demos/Device/ClassDriver/GenericHID/GenericHID.h
@@ -72,9 +72,9 @@
 		void EVENT_USB_ConfigurationChanged(void);
 		void EVENT_USB_UnhandledControlPacket(void);
 
-		uint16_t CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, uint8_t* const ReportID,
-		                                             void* ReportData);
-		void     CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, const uint8_t ReportID, 
-		                                              const void* ReportData, const uint16_t ReportSize);
+		bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, uint8_t* const ReportID,
+                                                 void* ReportData, uint16_t* ReportSize);
+		void CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, const uint8_t ReportID, 
+		                                          const void* ReportData, const uint16_t ReportSize);
 		
 #endif
diff --git a/Demos/Device/ClassDriver/Joystick/Joystick.c b/Demos/Device/ClassDriver/Joystick/Joystick.c
index ffd167ef5..f4dc32d9b 100644
--- a/Demos/Device/ClassDriver/Joystick/Joystick.c
+++ b/Demos/Device/ClassDriver/Joystick/Joystick.c
@@ -36,6 +36,9 @@
 
 #include "Joystick.h"
 
+/** Buffer to hold the previously generated HID report, for comparison purposes inside the HID class driver. */
+uint8_t PrevJoystickHIDReportBuffer[sizeof(USB_JoystickReport_Data_t)];
+
 /** LUFA HID Class driver interface configuration and state information. This structure is
  *  passed to all HID Class driver functions, so that multiple instances of the same class
  *  within a device can be differentiated from one another.
@@ -48,6 +51,9 @@ USB_ClassInfo_HID_Device_t Joystick_HID_Interface =
 
 				.ReportINEndpointNumber  = JOYSTICK_EPNUM,
 				.ReportINEndpointSize    = JOYSTICK_EPSIZE,
+
+				.PrevReportINBuffer      = PrevJoystickHIDReportBuffer,
+				.PrevReportINBufferSize  = sizeof(PrevJoystickHIDReportBuffer),
 			},
 	};
 
@@ -128,10 +134,12 @@ ISR(TIMER0_COMPA_vect, ISR_BLOCK)
  *  \param[in] HIDInterfaceInfo  Pointer to the HID class interface configuration structure being referenced
  *  \param[in,out] ReportID  Report ID requested by the host if non-zero, otherwise callback should set to the generated report ID
  *  \param[out] ReportData  Pointer to a buffer where the created report should be stored
+ *  \param[out] ReportSize  Number of bytes written in the report (or zero if no report is to be sent
  *
- *  \return Number of bytes written in the report (or zero if no report is to be sent
+ *  \return Boolean true to force the sending of the report, false to let the library determine if it needs to be sent
  */
-uint16_t CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, uint8_t* const ReportID, void* ReportData)
+bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, uint8_t* const ReportID,
+                                         void* ReportData, uint16_t* ReportSize)
 {
 	USB_JoystickReport_Data_t* JoystickReport = (USB_JoystickReport_Data_t*)ReportData;
 	
@@ -154,7 +162,8 @@ uint16_t CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const H
 	if (ButtonStatus_LCL & BUTTONS_BUTTON1)
 	  JoystickReport->Button |= (1 << 0);
 	  
-	return sizeof(USB_JoystickReport_Data_t);
+	*ReportSize = sizeof(USB_JoystickReport_Data_t);
+	return false;
 }
 
 /** HID class driver callback function for the processing of HID reports from the host.
diff --git a/Demos/Device/ClassDriver/Joystick/Joystick.h b/Demos/Device/ClassDriver/Joystick/Joystick.h
index 0f35fcce2..764de1723 100644
--- a/Demos/Device/ClassDriver/Joystick/Joystick.h
+++ b/Demos/Device/ClassDriver/Joystick/Joystick.h
@@ -83,9 +83,9 @@
 		void EVENT_USB_ConfigurationChanged(void);
 		void EVENT_USB_UnhandledControlPacket(void);
 
-		uint16_t CALLBACK_HID_Device_CreateNextHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, uint8_t* const ReportID,
-		                                                 void* ReportData);
-		void     CALLBACK_HID_Device_ProcessReceivedHIDReport(USB_ClassInfo_HID_Device_t* HIDInterfaceInfo, const uint8_t ReportID, 
-		                                                      const void* ReportData, const uint16_t ReportSize);
+		bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, uint8_t* const ReportID,
+                                                 void* ReportData, uint16_t* ReportSize);
+		void CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, const uint8_t ReportID, 
+		                                          const void* ReportData, const uint16_t ReportSize);
 
 #endif
diff --git a/Demos/Device/ClassDriver/Keyboard/Keyboard.c b/Demos/Device/ClassDriver/Keyboard/Keyboard.c
index fb19d02d9..040aec453 100644
--- a/Demos/Device/ClassDriver/Keyboard/Keyboard.c
+++ b/Demos/Device/ClassDriver/Keyboard/Keyboard.c
@@ -37,6 +37,9 @@
 
 #include "Keyboard.h"
 
+/** Buffer to hold the previously generated Keyboard HID report, for comparison purposes inside the HID class driver. */
+uint8_t PrevKeyboardHIDReportBuffer[sizeof(USB_KeyboardReport_Data_t)];
+
 /** LUFA HID Class driver interface configuration and state information. This structure is
  *  passed to all HID Class driver functions, so that multiple instances of the same class
  *  within a device can be differentiated from one another.
@@ -49,6 +52,9 @@ USB_ClassInfo_HID_Device_t Keyboard_HID_Interface =
 
 				.ReportINEndpointNumber  = KEYBOARD_EPNUM,
 				.ReportINEndpointSize    = KEYBOARD_EPSIZE,
+
+				.PrevReportINBuffer      = PrevKeyboardHIDReportBuffer,
+				.PrevReportINBufferSize  = sizeof(PrevKeyboardHIDReportBuffer),
 			},
     };
 
@@ -129,10 +135,12 @@ ISR(TIMER0_COMPA_vect, ISR_BLOCK)
  *  \param[in] HIDInterfaceInfo  Pointer to the HID class interface configuration structure being referenced
  *  \param[in,out] ReportID  Report ID requested by the host if non-zero, otherwise callback should set to the generated report ID
  *  \param[out] ReportData  Pointer to a buffer where the created report should be stored
+ *  \param[out] ReportSize  Number of bytes written in the report (or zero if no report is to be sent
  *
- *  \return Number of bytes written in the report (or zero if no report is to be sent
+ *  \return Boolean true to force the sending of the report, false to let the library determine if it needs to be sent
  */
-uint16_t CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, uint8_t* const ReportID, void* ReportData)
+bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, uint8_t* const ReportID,
+                                         void* ReportData, uint16_t* ReportSize)
 {
 	USB_KeyboardReport_Data_t* KeyboardReport = (USB_KeyboardReport_Data_t*)ReportData;
 	
@@ -154,8 +162,9 @@ uint16_t CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const H
 	  
 	if (ButtonStatus_LCL & BUTTONS_BUTTON1)
 	  KeyboardReport->KeyCode[0] = 0x09; // F
-	  
-	return sizeof(USB_KeyboardReport_Data_t);
+	
+	*ReportSize = sizeof(USB_KeyboardReport_Data_t);
+	return false;
 }
 
 /** HID class driver callback function for the processing of HID reports from the host.
diff --git a/Demos/Device/ClassDriver/Keyboard/Keyboard.h b/Demos/Device/ClassDriver/Keyboard/Keyboard.h
index 52b07ce60..4a28d20ff 100644
--- a/Demos/Device/ClassDriver/Keyboard/Keyboard.h
+++ b/Demos/Device/ClassDriver/Keyboard/Keyboard.h
@@ -86,9 +86,9 @@
 		void EVENT_USB_ConfigurationChanged(void);
 		void EVENT_USB_UnhandledControlPacket(void);
 
-		uint16_t CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, uint8_t* const ReportID,
-		                                             void* ReportData);
-		void     CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, const uint8_t ReportID, 
-		                                              const void* ReportData, const uint16_t ReportSize);
+		bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, uint8_t* const ReportID,
+                                                 void* ReportData, uint16_t* ReportSize);
+		void CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, const uint8_t ReportID, 
+		                                          const void* ReportData, const uint16_t ReportSize);
 
 #endif
diff --git a/Demos/Device/ClassDriver/KeyboardMouse/KeyboardMouse.c b/Demos/Device/ClassDriver/KeyboardMouse/KeyboardMouse.c
index 418ccba4e..abaf3808b 100644
--- a/Demos/Device/ClassDriver/KeyboardMouse/KeyboardMouse.c
+++ b/Demos/Device/ClassDriver/KeyboardMouse/KeyboardMouse.c
@@ -37,6 +37,12 @@
 
 #include "KeyboardMouse.h"
 
+/** Buffer to hold the previously generated Keyboard HID report, for comparison purposes inside the HID class driver. */
+uint8_t PrevKeyboardHIDReportBuffer[sizeof(USB_KeyboardReport_Data_t)];
+
+/** Buffer to hold the previously generated Mouse HID report, for comparison purposes inside the HID class driver. */
+uint8_t PrevMouseHIDReportBuffer[sizeof(USB_MouseReport_Data_t)];
+
 /** LUFA HID Class driver interface configuration and state information. This structure is
  *  passed to all HID Class driver functions, so that multiple instances of the same class
  *  within a device can be differentiated from one another. This is for the keyboard HID
@@ -50,6 +56,9 @@ USB_ClassInfo_HID_Device_t Keyboard_HID_Interface =
 
 				.ReportINEndpointNumber  = KEYBOARD_IN_EPNUM,
 				.ReportINEndpointSize    = HID_EPSIZE,
+
+				.PrevReportINBuffer      = PrevKeyboardHIDReportBuffer,
+				.PrevReportINBufferSize  = sizeof(PrevKeyboardHIDReportBuffer),
 			},
 	};
 	
@@ -66,6 +75,9 @@ USB_ClassInfo_HID_Device_t Mouse_HID_Interface =
 
 				.ReportINEndpointNumber  = MOUSE_IN_EPNUM,
 				.ReportINEndpointSize    = HID_EPSIZE,
+
+				.PrevReportINBuffer      = PrevMouseHIDReportBuffer,
+				.PrevReportINBufferSize  = sizeof(PrevMouseHIDReportBuffer),
 			},		
 	};
 
@@ -151,10 +163,12 @@ ISR(TIMER0_COMPA_vect, ISR_BLOCK)
  *  \param[in] HIDInterfaceInfo  Pointer to the HID class interface configuration structure being referenced
  *  \param[in,out] ReportID  Report ID requested by the host if non-zero, otherwise callback should set to the generated report ID
  *  \param[out] ReportData  Pointer to a buffer where the created report should be stored
+ *  \param[out] ReportSize  Number of bytes written in the report (or zero if no report is to be sent
  *
- *  \return Number of bytes written in the report (or zero if no report is to be sent
+ *  \return Boolean true to force the sending of the report, false to let the library determine if it needs to be sent
  */
-uint16_t CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, uint8_t* const ReportID, void* ReportData)
+bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, uint8_t* const ReportID,
+                                         void* ReportData, uint16_t* ReportSize)
 {
 	uint8_t JoyStatus_LCL    = Joystick_GetStatus();
 	uint8_t ButtonStatus_LCL = Buttons_GetStatus();
@@ -179,8 +193,9 @@ uint16_t CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const H
 
 		if (JoyStatus_LCL & JOY_PRESS)
 		  KeyboardReport->KeyCode[0] = 0x08; // E
-		  
-		return sizeof(USB_KeyboardReport_Data_t);
+		
+		*ReportSize = sizeof(USB_KeyboardReport_Data_t);
+		return false;
 	}
 	else
 	{
@@ -203,7 +218,8 @@ uint16_t CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const H
 		if (JoyStatus_LCL & JOY_PRESS)
 		  MouseReport->Button  = (1 << 0);
 		
-		return sizeof(USB_MouseReport_Data_t);		
+		*ReportSize = sizeof(USB_MouseReport_Data_t);
+		return true;		
 	}
 }
 
diff --git a/Demos/Device/ClassDriver/KeyboardMouse/KeyboardMouse.h b/Demos/Device/ClassDriver/KeyboardMouse/KeyboardMouse.h
index a04051bb9..15532c816 100644
--- a/Demos/Device/ClassDriver/KeyboardMouse/KeyboardMouse.h
+++ b/Demos/Device/ClassDriver/KeyboardMouse/KeyboardMouse.h
@@ -90,9 +90,9 @@
 		void EVENT_USB_ConfigurationChanged(void);
 		void EVENT_USB_UnhandledControlPacket(void);
 
-		uint16_t CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, uint8_t* const ReportID,
-		                                             void* ReportData);
-		void     CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, const uint8_t ReportID, 
-		                                              const void* ReportData, const uint16_t ReportSize);
+		bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, uint8_t* const ReportID,
+                                                 void* ReportData, uint16_t* ReportSize);
+		void CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, const uint8_t ReportID, 
+		                                          const void* ReportData, const uint16_t ReportSize);
 		
 #endif
diff --git a/Demos/Device/ClassDriver/Mouse/Mouse.c b/Demos/Device/ClassDriver/Mouse/Mouse.c
index 51021c0f5..08e87e672 100644
--- a/Demos/Device/ClassDriver/Mouse/Mouse.c
+++ b/Demos/Device/ClassDriver/Mouse/Mouse.c
@@ -36,6 +36,9 @@
 
 #include "Mouse.h"
 
+/** Buffer to hold the previously generated Mouse HID report, for comparison purposes inside the HID class driver. */
+uint8_t PrevMouseHIDReportBuffer[sizeof(USB_MouseReport_Data_t)];
+
 /** LUFA HID Class driver interface configuration and state information. This structure is
  *  passed to all HID Class driver functions, so that multiple instances of the same class
  *  within a device can be differentiated from one another.
@@ -48,6 +51,9 @@ USB_ClassInfo_HID_Device_t Mouse_HID_Interface =
 
 				.ReportINEndpointNumber  = MOUSE_EPNUM,
 				.ReportINEndpointSize    = MOUSE_EPSIZE,
+
+				.PrevReportINBuffer      = PrevMouseHIDReportBuffer,
+				.PrevReportINBufferSize  = sizeof(PrevMouseHIDReportBuffer),
 			},
 	};
 
@@ -128,10 +134,12 @@ ISR(TIMER0_COMPA_vect, ISR_BLOCK)
  *  \param[in] HIDInterfaceInfo  Pointer to the HID class interface configuration structure being referenced
  *  \param[in,out] ReportID  Report ID requested by the host if non-zero, otherwise callback should set to the generated report ID
  *  \param[out] ReportData  Pointer to a buffer where the created report should be stored
+ *  \param[out] ReportSize  Number of bytes written in the report (or zero if no report is to be sent
  *
- *  \return Number of bytes written in the report (or zero if no report is to be sent
+ *  \return Boolean true to force the sending of the report, false to let the library determine if it needs to be sent
  */
-uint16_t CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, uint8_t* const ReportID, void* ReportData)
+bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, uint8_t* const ReportID,
+                                         void* ReportData, uint16_t* ReportSize)
 {
 	USB_MouseReport_Data_t* MouseReport = (USB_MouseReport_Data_t*)ReportData;
 		
@@ -154,7 +162,8 @@ uint16_t CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const H
 	if (ButtonStatus_LCL & BUTTONS_BUTTON1)
 	  MouseReport->Button |= (1 << 1);
 	
-	return sizeof(USB_MouseReport_Data_t);
+	*ReportSize = sizeof(USB_MouseReport_Data_t);
+	return true;
 }
 
 /** HID class driver callback function for the processing of HID reports from the host.
diff --git a/Demos/Device/ClassDriver/Mouse/Mouse.h b/Demos/Device/ClassDriver/Mouse/Mouse.h
index f134d92dc..57e4a693d 100644
--- a/Demos/Device/ClassDriver/Mouse/Mouse.h
+++ b/Demos/Device/ClassDriver/Mouse/Mouse.h
@@ -85,9 +85,9 @@
 		void EVENT_USB_ConfigurationChanged(void);
 		void EVENT_USB_UnhandledControlPacket(void);
 
-		uint16_t CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, uint8_t* const ReportID,
-		                                             void* ReportData);
-		void     CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, const uint8_t ReportID, 
-		                                              const void* ReportData, const uint16_t ReportSize);
+		bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, uint8_t* const ReportID,
+                                                 void* ReportData, uint16_t* ReportSize);
+		void CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, const uint8_t ReportID, 
+		                                          const void* ReportData, const uint16_t ReportSize);
 
 #endif
diff --git a/LUFA/Drivers/USB/Class/Device/HID.c b/LUFA/Drivers/USB/Class/Device/HID.c
index eef15f26c..fbb45acd2 100644
--- a/LUFA/Drivers/USB/Class/Device/HID.c
+++ b/LUFA/Drivers/USB/Class/Device/HID.c
@@ -51,15 +51,15 @@ void HID_Device_ProcessControlPacket(USB_ClassInfo_HID_Device_t* const HIDInterf
 			{
 				Endpoint_ClearSETUP();	
 
-				uint8_t  ReportINData[HID_MAX_REPORT_SIZE];
 				uint16_t ReportINSize;
 				uint8_t  ReportID = (USB_ControlRequest.wValue & 0xFF);
 
-				memset(ReportINData, 0, sizeof(ReportINData));
+				memset(HIDInterfaceInfo->Config.PrevReportINBuffer, 0, HIDInterfaceInfo->Config.PrevReportINBufferSize);
 				
-				ReportINSize = CALLBACK_HID_Device_CreateHIDReport(HIDInterfaceInfo, &ReportID, ReportINData);
+				CALLBACK_HID_Device_CreateHIDReport(HIDInterfaceInfo, &ReportID,
+				                                    HIDInterfaceInfo->Config.PrevReportINBuffer, &ReportINSize);
 
-				Endpoint_Write_Control_Stream_LE(ReportINData, ReportINSize);
+				Endpoint_Write_Control_Stream_LE(HIDInterfaceInfo->Config.PrevReportINBuffer, ReportINSize);
 				Endpoint_ClearOUT();
 			}
 		
@@ -157,20 +157,20 @@ void HID_Device_USBTask(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo)
 	
 	if (Endpoint_IsReadWriteAllowed())
 	{
-		uint8_t  ReportINData[HID_MAX_REPORT_SIZE];
+		uint8_t  ReportINData[HIDInterfaceInfo->Config.PrevReportINBufferSize];
 		uint8_t  ReportID = 0;
 		uint16_t ReportINSize;
 
 		memset(ReportINData, 0, sizeof(ReportINData));
 
-		ReportINSize  = CALLBACK_HID_Device_CreateHIDReport(HIDInterfaceInfo, &ReportID, ReportINData);
+		bool ForceSend = CALLBACK_HID_Device_CreateHIDReport(HIDInterfaceInfo, &ReportID, ReportINData, &ReportINSize);
 
-		bool StatesChanged     = (memcmp(ReportINData, HIDInterfaceInfo->State.PreviousReportINData, ReportINSize) != 0);
+		bool StatesChanged     = (memcmp(ReportINData, HIDInterfaceInfo->Config.PrevReportINBuffer, ReportINSize) != 0);
 		bool IdlePeriodElapsed = (HIDInterfaceInfo->State.IdleCount && !(HIDInterfaceInfo->State.IdleMSRemaining));
 		
-		memcpy(HIDInterfaceInfo->State.PreviousReportINData, ReportINData, ReportINSize);
+		memcpy(HIDInterfaceInfo->Config.PrevReportINBuffer, ReportINData, ReportINSize);
 
-		if (ReportINSize && (StatesChanged || IdlePeriodElapsed))
+		if (ReportINSize && (ForceSend || StatesChanged || IdlePeriodElapsed))
 		{
 			HIDInterfaceInfo->State.IdleMSRemaining = HIDInterfaceInfo->State.IdleCount;
 
diff --git a/LUFA/Drivers/USB/Class/Device/HID.h b/LUFA/Drivers/USB/Class/Device/HID.h
index 06456cf8a..b8ca47980 100644
--- a/LUFA/Drivers/USB/Class/Device/HID.h
+++ b/LUFA/Drivers/USB/Class/Device/HID.h
@@ -56,17 +56,6 @@
 		#endif
 
 	/* Public Interface - May be used in end-application: */
-		/* Macros: */
-			#if !defined(HID_MAX_REPORT_SIZE)
-				/** Maximum size of an IN report which can be generated by the device and sent to the host, in bytes.
-				 *
-				 *  \note If larger reports than the default specified here are to be generated by the device, this
-				 *        value can be overridden by defining this token to the required value in the project makefile
-				 *        and passing it to the compiler via the -D switch.
-				 */
-				#define HID_MAX_REPORT_SIZE     16
-			#endif
-	
 		/* Type Defines: */
 			/** Class state structure. An instance of this structure should be made for each HID interface
 			 *  within the user application, and passed to each of the HID class driver functions as the
@@ -80,6 +69,16 @@
 
 					uint8_t  ReportINEndpointNumber; /**< Endpoint number of the HID interface's IN report endpoint */
 					uint16_t ReportINEndpointSize; /**< Size in bytes of the HID interface's IN report endpoint */					
+					
+					void*    PrevReportINBuffer; /** Pointer to a buffer where the previously created HID input report can be
+					                              *  stored by the driver, for comparison purposes to detect report changes that
+					                              *  must be sent immediately to the host. This should point to a buffer big enough
+					                              *  to hold the largest HID input report sent from the HID interface.
+					                              */
+					uint8_t  PrevReportINBufferSize; /** Size in bytes of the given input report buffer. This is used to create a
+					                                  *  second buffer of the same size within the driver so that subsequent reports
+					                                  *  can be compared.
+					                                  */
 				} Config; /**< Config data for the USB class interface within the device. All elements in this section
 				           *   <b>must</b> be set or the interface will fail to enumerate and operate correctly.
 				           */										 
@@ -89,8 +88,6 @@
 					uint16_t IdleCount; /**< Report idle period, in mS, set by the host */
 					uint16_t IdleMSRemaining; /**< Total number of mS remaining before the idle period elapsed - this should be
 											   *   decremented by the user application if non-zero each millisecond */	
-
-					uint8_t PreviousReportINData[HID_MAX_REPORT_SIZE]; /**< Previously generated report from the HID interface */
 				} State; /**< State data for the USB class interface within the device. All elements in this section
 				          *   are reset to their defaults when the interface is enumerated.
 				          */
@@ -137,11 +134,14 @@
 			 *                 be set to the report ID of the generated HID input report. If multiple reports are not sent via the
 			 *                 given HID interface, this parameter should be ignored.
 			 *  \param[out] ReportData  Pointer to a buffer where the generated HID report should be stored.
+			 *  \param[out] ReportSize  Number of bytes in the generated input report, or zero if no report is to be sent
 			 *
-			 *  \return  Number of bytes in the generated input report, or zero if no report is to be sent
+			 *  \return Boolean true to force the sending of the report even if it is identical to the previous report and still within
+			 *          the idle period (useful for devices which report relative movement), false otherwise
 			 */
-			uint16_t CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* HIDInterfaceInfo, uint8_t* ReportID, void* ReportData);
-
+			bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, uint8_t* const ReportID,
+                                                     void* ReportData, uint16_t* ReportSize);
+			
 			/** HID class driver callback for the user processing of a received HID input report. This callback may fire in response to
 			 *  either HID class control requests from the host, or by the normal HID endpoint polling procedure. Inside this callback
 			 *  the user is responsible for the processing of the received HID output report from the host.
diff --git a/Projects/Magstripe/Magstripe.c b/Projects/Magstripe/Magstripe.c
index 6d463d6a8..f0fd8a7d0 100644
--- a/Projects/Magstripe/Magstripe.c
+++ b/Projects/Magstripe/Magstripe.c
@@ -45,6 +45,9 @@ BitBuffer_t TrackDataBuffers[TOTAL_TRACKS];
 /** Pointer to the current track buffer being sent to the host. */
 BitBuffer_t* CurrentTrackBuffer = &TrackDataBuffers[TOTAL_TRACKS];
 
+/** Buffer to hold the previously generated Keyboard HID report, for comparison purposes inside the HID class driver. */
+uint8_t PrevKeyboardHIDReportBuffer[sizeof(USB_KeyboardReport_Data_t)];
+
 /** LUFA HID Class driver interface configuration and state information. This structure is
  *  passed to all HID Class driver functions, so that multiple instances of the same class
  *  within a device can be differentiated from one another.
@@ -57,6 +60,9 @@ USB_ClassInfo_HID_Device_t Keyboard_HID_Interface =
 
 				.ReportINEndpointNumber  = KEYBOARD_EPNUM,
 				.ReportINEndpointSize    = KEYBOARD_EPSIZE,
+
+				.PrevReportINBuffer      = PrevKeyboardHIDReportBuffer,
+				.PrevReportINBufferSize  = sizeof(PrevKeyboardHIDReportBuffer),
 			},
 	};
 
@@ -156,15 +162,17 @@ ISR(TIMER0_COMPA_vect, ISR_BLOCK)
 	HID_Device_MillisecondElapsed(&Keyboard_HID_Interface);
 }
 
-/** HID Class driver callback function for the creation of a HID report for the host.
+/** HID class driver callback function for the creation of HID reports to the host.
  *
- *  \param[in] HIDInterfaceInfo  Pointer to the HID interface structure for the HID interface being referenced
- *  \param[in,out] ReportID      Report ID requested by the host if non-zero, otherwise callback should set to the generated report ID
- *  \param[out] ReportData       Pointer to the preallocated report buffer where the created report should be stored
+ *  \param[in] HIDInterfaceInfo  Pointer to the HID class interface configuration structure being referenced
+ *  \param[in,out] ReportID  Report ID requested by the host if non-zero, otherwise callback should set to the generated report ID
+ *  \param[out] ReportData  Pointer to a buffer where the created report should be stored
+ *  \param[out] ReportSize  Number of bytes written in the report (or zero if no report is to be sent
  *
- *  \return Number of bytes in the created report
+ *  \return Boolean true to force the sending of the report, false to let the library determine if it needs to be sent
  */
-uint16_t CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, uint8_t* const ReportID, void* ReportData)
+bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, uint8_t* const ReportID,
+                                         void* ReportData, uint16_t* ReportSize)
 {
 	USB_KeyboardReport_Data_t* KeyboardReport = (USB_KeyboardReport_Data_t*)ReportData;
 
@@ -190,7 +198,8 @@ uint16_t CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const H
 		KeyboardReport->KeyCode = BitBuffer_GetNextBit(CurrentTrackBuffer) ? KEY_1 : KEY_0;
 	}
 	
-	return sizeof(USB_KeyboardReport_Data_t);
+	*ReportSize = sizeof(USB_KeyboardReport_Data_t);
+	return false;
 }
 
 /** HID Class driver callback function for the processing of a received HID report from the host.
diff --git a/Projects/Magstripe/Magstripe.h b/Projects/Magstripe/Magstripe.h
index 4e0aac979..279e3db2e 100644
--- a/Projects/Magstripe/Magstripe.h
+++ b/Projects/Magstripe/Magstripe.h
@@ -85,9 +85,9 @@
 		void EVENT_USB_ConfigurationChanged(void);
 		void EVENT_USB_UnhandledControlPacket(void);
 
-		uint16_t CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, uint8_t* const ReportID,
-		                                             void* ReportData);
-		void CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, const uint8_t ReportID,
-                                                  const void* ReportData, const uint16_t ReportSize);
+		bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, uint8_t* const ReportID,
+                                                 void* ReportData, uint16_t* ReportSize);
+		void CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, const uint8_t ReportID, 
+		                                          const void* ReportData, const uint16_t ReportSize);
 														  
 #endif
-- 
GitLab