From 958a1b4e2bffdc548b34edd322d30cec5d5feacd Mon Sep 17 00:00:00 2001 From: Dean Camera Date: Tue, 12 May 2009 08:28:02 +0000 Subject: Fixed Mouse and Keyboard device demos not acting in accordance with the HID specification for idle periods (thanks to Brian Dickman). Removed support for endpoint/pipe non-control interrupts; these did not act in the way users expected, and had many subtle issues. --- Demos/Device/GenericHID/GenericHID.c | 72 +------------------ Demos/Device/GenericHID/GenericHID.txt | 7 -- Demos/Device/Keyboard/Keyboard.c | 104 +++++++-------------------- Demos/Device/Keyboard/Keyboard.h | 7 +- Demos/Device/Keyboard/Keyboard.txt | 7 -- Demos/Device/MassStorage/MassStorage.c | 3 - Demos/Device/Mouse/Mouse.c | 82 ++++++++------------- Demos/Device/Mouse/Mouse.h | 15 ++-- Demos/Device/Mouse/Mouse.txt | 7 -- Demos/Device/RNDISEthernet/RNDISConstants.h | 2 +- Demos/Host/GenericHIDHost/GenericHIDHost.c | 38 ---------- Demos/Host/GenericHIDHost/GenericHIDHost.txt | 13 +--- Demos/Host/KeyboardHost/KeyboardHost.c | 48 +------------ Demos/Host/KeyboardHost/KeyboardHost.txt | 13 +--- Demos/Host/MouseHost/MouseHost.c | 46 ------------ Demos/Host/MouseHost/MouseHost.txt | 13 +--- Demos/OTG/TestApp/TestEvents.c | 2 + LUFA.pnproj | 2 +- LUFA/ChangeLog.txt | 2 + LUFA/Drivers/USB/LowLevel/Endpoint.h | 37 ---------- LUFA/Drivers/USB/LowLevel/HostChapter9.c | 2 +- LUFA/Drivers/USB/LowLevel/Pipe.h | 36 ---------- LUFA/MigrationInformation.txt | 10 +++ 23 files changed, 98 insertions(+), 470 deletions(-) diff --git a/Demos/Device/GenericHID/GenericHID.c b/Demos/Device/GenericHID/GenericHID.c index 695342d0e..d4e7cca73 100644 --- a/Demos/Device/GenericHID/GenericHID.c +++ b/Demos/Device/GenericHID/GenericHID.c @@ -43,9 +43,7 @@ TASK_LIST { .Task = USB_USBTask , .TaskStatus = TASK_STOP }, #endif - #if !defined(INTERRUPT_DATA_ENDPOINT) { .Task = USB_HID_Report , .TaskStatus = TASK_STOP }, - #endif }; /** Static buffer to hold the last received report from the host, so that it can be echoed back in the next sent report */ @@ -112,9 +110,7 @@ EVENT_HANDLER(USB_Connect) EVENT_HANDLER(USB_Disconnect) { /* Stop running HID reporting and USB management tasks */ - #if !defined(INTERRUPT_DATA_ENDPOINT) Scheduler_SetTaskMode(USB_HID_Report, TASK_STOP); - #endif #if !defined(INTERRUPT_CONTROL_ENDPOINT) Scheduler_SetTaskMode(USB_USBTask, TASK_STOP); @@ -134,21 +130,11 @@ EVENT_HANDLER(USB_ConfigurationChanged) ENDPOINT_DIR_IN, GENERIC_EPSIZE, ENDPOINT_BANK_SINGLE); - #if defined(INTERRUPT_DATA_ENDPOINT) - /* Enable the endpoint IN interrupt ISR for the report endpoint */ - USB_INT_Enable(ENDPOINT_INT_IN); - #endif - /* Setup Generic OUT Report Endpoint */ Endpoint_ConfigureEndpoint(GENERIC_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT, GENERIC_EPSIZE, ENDPOINT_BANK_SINGLE); - #if defined(INTERRUPT_DATA_ENDPOINT) - /* Enable the endpoint OUT interrupt ISR for the report endpoint */ - USB_INT_Enable(ENDPOINT_INT_OUT); - #endif - /* Indicate USB connected and ready */ UpdateStatus(Status_USBReady); } @@ -266,7 +252,6 @@ void CreateGenericHIDReport(uint8_t* DataArray) DataArray[i] = LastReceived[i]; } -#if !defined(INTERRUPT_DATA_ENDPOINT) TASK(USB_HID_Report) { /* Check if the USB system is connected to a host */ @@ -313,8 +298,8 @@ TASK(USB_HID_Report) } } } -#endif +#if defined(INTERRUPT_CONTROL_ENDPOINT) /** ISR for the general Pipe/Endpoint interrupt vector. This ISR fires when an endpoint's status changes (such as * a packet has been received) on an endpoint with its corresponding ISR enabling bits set. This is used to send * HID packets to the host each time the HID interrupt endpoints polling period elapses, as managed by the USB @@ -325,7 +310,6 @@ ISR(ENDPOINT_PIPE_vect, ISR_BLOCK) /* Save previously selected endpoint before selecting a new endpoint */ uint8_t PrevSelectedEndpoint = Endpoint_GetCurrentEndpoint(); - #if defined(INTERRUPT_CONTROL_ENDPOINT) /* Check if the control endpoint has received a request */ if (Endpoint_HasEndpointInterrupted(ENDPOINT_CONTROLEP)) { @@ -338,60 +322,8 @@ ISR(ENDPOINT_PIPE_vect, ISR_BLOCK) /* Handshake the endpoint setup interrupt - must be after the call to USB_USBTask() */ USB_INT_Clear(ENDPOINT_INT_SETUP); } - #endif - - #if defined(INTERRUPT_DATA_ENDPOINT) - /* Check if Generic IN endpoint has interrupted */ - if (Endpoint_HasEndpointInterrupted(GENERIC_IN_EPNUM)) - { - /* Select the Generic IN Report Endpoint */ - Endpoint_SelectEndpoint(GENERIC_IN_EPNUM); - - /* Clear the endpoint IN interrupt flag */ - USB_INT_Clear(ENDPOINT_INT_IN); - - /* Clear the Generic IN Report endpoint interrupt and select the endpoint */ - Endpoint_ClearEndpointInterrupt(GENERIC_IN_EPNUM); - - /* Create a temporary buffer to hold the report to send to the host */ - uint8_t GenericData[GENERIC_REPORT_SIZE]; - - /* Create Generic Report Data */ - CreateGenericHIDReport(GenericData); - - /* Write Generic Report Data */ - Endpoint_Write_Stream_LE(&GenericData, sizeof(GenericData)); - - /* Finalize the stream transfer to send the last packet */ - Endpoint_ClearIN(); - } - - /* Check if Generic OUT endpoint has interrupted */ - if (Endpoint_HasEndpointInterrupted(GENERIC_OUT_EPNUM)) - { - /* Select the Generic OUT Report Endpoint */ - Endpoint_SelectEndpoint(GENERIC_OUT_EPNUM); - - /* Clear the endpoint OUT Interrupt flag */ - USB_INT_Clear(ENDPOINT_INT_OUT); - - /* Clear the Generic OUT Report endpoint interrupt and select the endpoint */ - Endpoint_ClearEndpointInterrupt(GENERIC_OUT_EPNUM); - - /* Create a temporary buffer to hold the read in report from the host */ - uint8_t GenericData[GENERIC_REPORT_SIZE]; - - /* Read Generic Report Data */ - Endpoint_Read_Stream_LE(&GenericData, sizeof(GenericData)); - - /* Process Generic Report Data */ - ProcessGenericHIDReport(GenericData); - - /* Finalize the stream transfer to send the last packet */ - Endpoint_ClearOUT(); - } - #endif /* Restore previously selected endpoint */ Endpoint_SelectEndpoint(PrevSelectedEndpoint); } +#endif diff --git a/Demos/Device/GenericHID/GenericHID.txt b/Demos/Device/GenericHID/GenericHID.txt index 2e092cf3a..c78f63753 100644 --- a/Demos/Device/GenericHID/GenericHID.txt +++ b/Demos/Device/GenericHID/GenericHID.txt @@ -67,12 +67,5 @@ * which services control requests from the host. If not defined, the control endpoint * is serviced via polling using the task scheduler. * - * - * INTERRUPT_DATA_ENDPOINT - * Makefile CDEFS - * When defined, this causes the demo to enable interrupts for the data endpoints, - * which services incoming LED reports and outgoing key status reports to and from the host. - * If not defined, the data endpoints are serviced via polling using the task scheduler. - * * */ diff --git a/Demos/Device/Keyboard/Keyboard.c b/Demos/Device/Keyboard/Keyboard.c index 33545bff6..7b9317265 100644 --- a/Demos/Device/Keyboard/Keyboard.c +++ b/Demos/Device/Keyboard/Keyboard.c @@ -56,9 +56,9 @@ TASK_LIST bool UsingReportProtocol = true; /** Current Idle period. This is set by the host via a Set Idle HID class request to silence the device's reports - * for either the entire idle duration, or until the report status changes (e.g. the user moves the mouse). + * for either the entire idle duration, or until the report status changes (e.g. the user presses a key). */ -uint8_t IdleCount = 0; +uint16_t IdleCount = 500; /** Current Idle period remaining. When the IdleCount value is set, this tracks the remaining number of idle * milliseconds. This is separate to the IdleCount timer and is incremented and compared as the host may request @@ -140,9 +140,7 @@ EVENT_HANDLER(USB_Reset) EVENT_HANDLER(USB_Disconnect) { /* Stop running keyboard reporting and USB management tasks */ - #if !defined(INTERRUPT_DATA_ENDPOINT) Scheduler_SetTaskMode(USB_Keyboard_Report, TASK_STOP); - #endif #if !defined(INTERRUPT_CONTROL_ENDPOINT) Scheduler_SetTaskMode(USB_USBTask, TASK_STOP); @@ -162,28 +160,16 @@ EVENT_HANDLER(USB_ConfigurationChanged) ENDPOINT_DIR_IN, KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE); - #if defined(INTERRUPT_DATA_ENDPOINT) - /* Enable the endpoint IN interrupt ISR for the report endpoint */ - USB_INT_Enable(ENDPOINT_INT_IN); - #endif - /* Setup Keyboard LED Report Endpoint */ Endpoint_ConfigureEndpoint(KEYBOARD_LEDS_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT, KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE); - #if defined(INTERRUPT_DATA_ENDPOINT) - /* Enable the endpoint OUT interrupt ISR for the LED report endpoint */ - USB_INT_Enable(ENDPOINT_INT_OUT); - #endif - /* Indicate USB connected and ready */ UpdateStatus(Status_USBReady); - #if !defined(INTERRUPT_DATA_ENDPOINT) /* Start running keyboard reporting task */ Scheduler_SetTaskMode(USB_Keyboard_Report, TASK_RUN); - #endif } /** Event handler for the USB_UnhandledControlPacket event. This is used to catch standard and class specific @@ -358,7 +344,7 @@ void ProcessLEDReport(uint8_t LEDReport) } /** Sends the next HID report to the host, via the keyboard data endpoint. */ -static inline void SendNextReport(void) +void SendNextReport(void) { static USB_KeyboardReport_Data_t PrevKeyboardReportData; USB_KeyboardReport_Data_t KeyboardReportData; @@ -367,41 +353,38 @@ static inline void SendNextReport(void) /* Create the next keyboard report for transmission to the host */ CreateKeyboardReport(&KeyboardReportData); - /* Check if the idle period is set */ - if (IdleCount) - { - /* Check if idle period has elapsed */ - if (!(IdleMSRemaining)) - { - /* Reset the idle time remaining counter, must multiply by 4 to get the duration in milliseconds */ - IdleMSRemaining = (IdleCount << 2); - } - else - { - /* Idle period not elapsed, indicate that a report must not be sent unless the report has changed */ - SendReport = (memcmp(&PrevKeyboardReportData, &KeyboardReportData, sizeof(USB_KeyboardReport_Data_t)) != 0); - } - } + /* Check to see if the report data has changed - if so a report MUST be sent */ + SendReport = (memcmp(&PrevKeyboardReportData, &KeyboardReportData, sizeof(USB_KeyboardReport_Data_t)) != 0); /* Save the current report data for later comparison to check for changes */ PrevKeyboardReportData = KeyboardReportData; - + + /* Check if the idle period is set and has elapsed */ + if ((IdleCount != HID_IDLE_CHANGESONLY) && (!(IdleMSRemaining))) + { + /* Reset the idle time remaining counter, must multiply by 4 to get the duration in milliseconds */ + IdleMSRemaining = (IdleCount << 2); + + /* Idle period is set and has elapsed, must send a report to the host */ + SendReport = true; + } + /* Select the Keyboard Report Endpoint */ Endpoint_SelectEndpoint(KEYBOARD_EPNUM); - /* Check if Keyboard Endpoint Ready for Read/Write, and if we should send a report */ + /* Check if Keyboard Endpoint Ready for Read/Write and if we should send a new report */ if (Endpoint_IsReadWriteAllowed() && SendReport) { /* Write Keyboard Report Data */ Endpoint_Write_Stream_LE(&KeyboardReportData, sizeof(KeyboardReportData)); - + /* Finalize the stream transfer to send the last packet */ Endpoint_ClearIN(); } } /** Reads the next LED status report from the host from the LED data endpoint, if one has been sent. */ -static inline void ReceiveNextReport(void) +void ReceiveNextReport(void) { /* Select the Keyboard LED Report Endpoint */ Endpoint_SelectEndpoint(KEYBOARD_LEDS_EPNUM); @@ -451,7 +434,6 @@ void UpdateStatus(uint8_t CurrentStatus) LEDs_SetAllLEDs(LEDMask); } -#if !defined(INTERRUPT_DATA_ENDPOINT) /** Function to manage HID report generation and transmission to the host, when in report mode. */ TASK(USB_Keyboard_Report) { @@ -465,8 +447,8 @@ TASK(USB_Keyboard_Report) ReceiveNextReport(); } } -#endif +#if defined(INTERRUPT_CONTROL_ENDPOINT) /** ISR for the general Pipe/Endpoint interrupt vector. This ISR fires when an endpoint's status changes (such as * a packet has been received) on an endpoint with its corresponding ISR enabling bits set. This is used to send * HID packets to the host each time the HID interrupt endpoints polling period elapses, as managed by the USB @@ -475,52 +457,20 @@ TASK(USB_Keyboard_Report) */ ISR(ENDPOINT_PIPE_vect, ISR_BLOCK) { - #if defined(INTERRUPT_CONTROL_ENDPOINT) + /* Save previously selected endpoint before selecting a new endpoint */ + uint8_t PrevSelectedEndpoint = Endpoint_GetCurrentEndpoint(); + /* Check if the control endpoint has received a request */ if (Endpoint_HasEndpointInterrupted(ENDPOINT_CONTROLEP)) { - /* Clear the endpoint interrupt */ - Endpoint_ClearEndpointInterrupt(ENDPOINT_CONTROLEP); - /* Process the control request */ USB_USBTask(); /* Handshake the endpoint setup interrupt - must be after the call to USB_USBTask() */ USB_INT_Clear(ENDPOINT_INT_SETUP); } - #endif - - #if defined(INTERRUPT_DATA_ENDPOINT) - /* Check if keyboard endpoint has interrupted */ - if (Endpoint_HasEndpointInterrupted(KEYBOARD_EPNUM)) - { - /* Select the Keyboard Report Endpoint */ - Endpoint_SelectEndpoint(KEYBOARD_EPNUM); - - /* Clear the endpoint IN interrupt flag */ - USB_INT_Clear(ENDPOINT_INT_IN); - - /* Clear the Keyboard Report endpoint interrupt */ - Endpoint_ClearEndpointInterrupt(KEYBOARD_EPNUM); - - /* Send the next keypress report to the host */ - SendNextReport(); - } - - /* Check if Keyboard LED status Endpoint has interrupted */ - if (Endpoint_HasEndpointInterrupted(KEYBOARD_LEDS_EPNUM)) - { - /* Select the Keyboard LED Report Endpoint */ - Endpoint_SelectEndpoint(KEYBOARD_LEDS_EPNUM); - - /* Clear the endpoint OUT interrupt flag */ - USB_INT_Clear(ENDPOINT_INT_OUT); - - /* Clear the Keyboard LED Report endpoint interrupt */ - Endpoint_ClearEndpointInterrupt(KEYBOARD_LEDS_EPNUM); - - /* Process the LED report sent from the host */ - ReceiveNextReport(); - } - #endif + + /* Restore previously selected endpoint */ + Endpoint_SelectEndpoint(PrevSelectedEndpoint); } +#endif diff --git a/Demos/Device/Keyboard/Keyboard.h b/Demos/Device/Keyboard/Keyboard.h index 76b770582..c73701905 100644 --- a/Demos/Device/Keyboard/Keyboard.h +++ b/Demos/Device/Keyboard/Keyboard.h @@ -54,6 +54,9 @@ #include // LEDs driver /* Macros: */ + /** Idle period indicating that reports should be sent only when the inputs have changed */ + #define HID_IDLE_CHANGESONLY 0 + /** HID Class specific request to get the next HID report from the device. */ #define REQ_GetReport 0x01 @@ -114,8 +117,8 @@ /* Function Prototypes: */ void CreateKeyboardReport(USB_KeyboardReport_Data_t* ReportData); void ProcessLEDReport(uint8_t LEDReport); - static inline void SendNextReport(void); - static inline void ReceiveNextReport(void); + void SendNextReport(void); + void ReceiveNextReport(void); void UpdateStatus(uint8_t CurrentStatus); #endif diff --git a/Demos/Device/Keyboard/Keyboard.txt b/Demos/Device/Keyboard/Keyboard.txt index fd95e455e..39df2a171 100644 --- a/Demos/Device/Keyboard/Keyboard.txt +++ b/Demos/Device/Keyboard/Keyboard.txt @@ -63,12 +63,5 @@ * which services control requests from the host. If not defined, the control endpoint * is serviced via polling using the task scheduler. * - * - * INTERRUPT_DATA_ENDPOINT - * Makefile CDEFS - * When defined, this causes the demo to enable interrupts for the data endpoints, - * which services incoming LED reports and outgoing key status reports to and from the host. - * If not defined, the data endpoints are serviced via polling using the task scheduler. - * * */ diff --git a/Demos/Device/MassStorage/MassStorage.c b/Demos/Device/MassStorage/MassStorage.c index e2c242499..b24018a10 100644 --- a/Demos/Device/MassStorage/MassStorage.c +++ b/Demos/Device/MassStorage/MassStorage.c @@ -387,9 +387,6 @@ ISR(ENDPOINT_PIPE_vect, ISR_BLOCK) /* Check if the control endpoint has received a request */ if (Endpoint_HasEndpointInterrupted(ENDPOINT_CONTROLEP)) { - /* Clear the endpoint interrupt */ - Endpoint_ClearEndpointInterrupt(ENDPOINT_CONTROLEP); - /* Process the control request */ USB_USBTask(); diff --git a/Demos/Device/Mouse/Mouse.c b/Demos/Device/Mouse/Mouse.c index 763d366e9..8998530d8 100644 --- a/Demos/Device/Mouse/Mouse.c +++ b/Demos/Device/Mouse/Mouse.c @@ -43,9 +43,7 @@ TASK_LIST { .Task = USB_USBTask , .TaskStatus = TASK_STOP }, #endif - #if !defined(INTERRUPT_DATA_ENDPOINT) { .Task = USB_Mouse_Report , .TaskStatus = TASK_STOP }, - #endif }; /* Global Variables */ @@ -57,7 +55,7 @@ bool UsingReportProtocol = true; /** Current Idle period. This is set by the host via a Set Idle HID class request to silence the device's reports * for either the entire idle duration, or until the report status changes (e.g. the user moves the mouse). */ -uint8_t IdleCount = 0; +uint16_t IdleCount = HID_IDLE_CHANGESONLY; /** Current Idle period remaining. When the IdleCount value is set, this tracks the remaining number of idle * milliseconds. This is separate to the IdleCount timer and is incremented and compared as the host may request @@ -140,9 +138,7 @@ EVENT_HANDLER(USB_Reset) EVENT_HANDLER(USB_Disconnect) { /* Stop running mouse reporting and USB management tasks */ - #if !defined(INTERRUPT_DATA_ENDPOINT) Scheduler_SetTaskMode(USB_Mouse_Report, TASK_STOP); - #endif #if !defined(INTERRUPT_CONTROL_ENDPOINT) Scheduler_SetTaskMode(USB_USBTask, TASK_STOP); @@ -162,18 +158,11 @@ EVENT_HANDLER(USB_ConfigurationChanged) ENDPOINT_DIR_IN, MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE); - #if defined(INTERRUPT_DATA_ENDPOINT) - /* Enable the endpoint IN interrupt ISR for the report endpoint */ - USB_INT_Enable(ENDPOINT_INT_IN); - #endif - /* Indicate USB connected and ready */ UpdateStatus(Status_USBReady); - #if !defined(INTERRUPT_DATA_ENDPOINT) /* Start running mouse reporting task */ Scheduler_SetTaskMode(USB_Mouse_Report, TASK_RUN); - #endif } /** Event handler for the USB_UnhandledControlPacket event. This is used to catch standard and class specific @@ -311,34 +300,36 @@ void CreateMouseReport(USB_MouseReport_Data_t* ReportData) } /** Sends the next HID report to the host, via the keyboard data endpoint. */ -static inline void SendNextReport(void) +void SendNextReport(void) { static USB_MouseReport_Data_t PrevMouseReportData; USB_MouseReport_Data_t MouseReportData; - bool SendReport = true; + bool SendReport; /* Create the next mouse report for transmission to the host */ CreateMouseReport(&MouseReportData); - /* Check if the idle period is set*/ - if (IdleCount) - { - /* Determine if the idle period has elapsed */ - if (!(IdleMSRemaining)) - { - /* Reset the idle time remaining counter, must multiply by 4 to get the duration in milliseconds */ - IdleMSRemaining = (IdleCount << 2); - } - else - { - /* Idle period not elapsed, indicate that a report must not be sent unless the report has changed */ - SendReport = (memcmp(&PrevMouseReportData, &MouseReportData, sizeof(USB_MouseReport_Data_t)) != 0); - } - } - + /* Check to see if the report data has changed - if so a report MUST be sent */ + SendReport = (memcmp(&PrevMouseReportData, &MouseReportData, sizeof(USB_MouseReport_Data_t)) != 0); + + /* Override the check if the Y or X values are non-zero - we want continuous movement while the joystick + * is being held down (via continuous reports), otherwise the cursor will only move once per joystick toggle */ + if ((MouseReportData.Y != 0) || (MouseReportData.X != 0)) + SendReport = true; + /* Save the current report data for later comparison to check for changes */ PrevMouseReportData = MouseReportData; + /* Check if the idle period is set and has elapsed */ + if ((IdleCount != HID_IDLE_CHANGESONLY) && (!(IdleMSRemaining))) + { + /* Reset the idle time remaining counter, must multiply by 4 to get the duration in milliseconds */ + IdleMSRemaining = (IdleCount << 2); + + /* Idle period is set and has elapsed, must send a report to the host */ + SendReport = true; + } + /* Select the Mouse Report Endpoint */ Endpoint_SelectEndpoint(MOUSE_EPNUM); @@ -380,7 +371,6 @@ void UpdateStatus(uint8_t CurrentStatus) LEDs_SetAllLEDs(LEDMask); } -#if !defined(INTERRUPT_DATA_ENDPOINT) /** Task to manage HID report generation and transmission to the host, when in report mode. */ TASK(USB_Mouse_Report) { @@ -391,8 +381,8 @@ TASK(USB_Mouse_Report) SendNextReport(); } } -#endif +#if defined(INTERRUPT_CONTROL_ENDPOINT) /** ISR for the general Pipe/Endpoint interrupt vector. This ISR fires when an endpoint's status changes (such as * a packet has been received) on an endpoint with its corresponding ISR enabling bits set. This is used to send * HID packets to the host each time the HID interrupt endpoints polling period elapses, as managed by the USB @@ -401,36 +391,20 @@ TASK(USB_Mouse_Report) */ ISR(ENDPOINT_PIPE_vect, ISR_BLOCK) { - #if defined(INTERRUPT_CONTROL_ENDPOINT) + /* Save previously selected endpoint before selecting a new endpoint */ + uint8_t PrevSelectedEndpoint = Endpoint_GetCurrentEndpoint(); + /* Check if the control endpoint has received a request */ if (Endpoint_HasEndpointInterrupted(ENDPOINT_CONTROLEP)) { - /* Clear the endpoint interrupt */ - Endpoint_ClearEndpointInterrupt(ENDPOINT_CONTROLEP); - /* Process the control request */ USB_USBTask(); /* Handshake the endpoint setup interrupt - must be after the call to USB_USBTask() */ USB_INT_Clear(ENDPOINT_INT_SETUP); } - #endif - - #if defined(INTERRUPT_DATA_ENDPOINT) - /* Check if mouse endpoint has interrupted */ - if (Endpoint_HasEndpointInterrupted(MOUSE_EPNUM)) - { - /* Select the Mouse Report Endpoint */ - Endpoint_SelectEndpoint(MOUSE_EPNUM); - /* Clear the endpoint IN interrupt flag */ - USB_INT_Clear(ENDPOINT_INT_IN); - - /* Clear the Mouse Report endpoint interrupt and select the endpoint */ - Endpoint_ClearEndpointInterrupt(MOUSE_EPNUM); - - /* Send the next mouse report to the host */ - SendNextReport(); - } - #endif + /* Restore previously selected endpoint */ + Endpoint_SelectEndpoint(PrevSelectedEndpoint); } +#endif diff --git a/Demos/Device/Mouse/Mouse.h b/Demos/Device/Mouse/Mouse.h index 4eaf457ca..afa5a6a55 100644 --- a/Demos/Device/Mouse/Mouse.h +++ b/Demos/Device/Mouse/Mouse.h @@ -57,23 +57,26 @@ TASK(USB_Mouse_Report); /* Macros: */ + /** Idle period indicating that reports should be sent only when the inputs have changed */ + #define HID_IDLE_CHANGESONLY 0 + /** HID Class specific request to get the next HID report from the device. */ - #define REQ_GetReport 0x01 + #define REQ_GetReport 0x01 /** HID Class specific request to get the idle timeout period of the device. */ - #define REQ_GetIdle 0x02 + #define REQ_GetIdle 0x02 /** HID Class specific request to send the next HID report to the device. */ - #define REQ_SetReport 0x09 + #define REQ_SetReport 0x09 /** HID Class specific request to set the idle timeout period of the device. */ - #define REQ_SetIdle 0x0A + #define REQ_SetIdle 0x0A /** HID Class specific request to get the current HID protocol in use, either report or boot. */ - #define REQ_GetProtocol 0x03 + #define REQ_GetProtocol 0x03 /** HID Class specific request to set the current HID protocol in use, either report or boot. */ - #define REQ_SetProtocol 0x0B + #define REQ_SetProtocol 0x0B /* Type Defines: */ /** Type define for the mouse HID report structure, for creating and sending HID reports to the host PC. diff --git a/Demos/Device/Mouse/Mouse.txt b/Demos/Device/Mouse/Mouse.txt index 2d566ddeb..a3bf024d5 100644 --- a/Demos/Device/Mouse/Mouse.txt +++ b/Demos/Device/Mouse/Mouse.txt @@ -64,12 +64,5 @@ * which services control requests from the host. If not defined, the control endpoint * is serviced via polling using the task scheduler. * - * - * INTERRUPT_DATA_ENDPOINT - * Makefile CDEFS - * When defined, this causes the demo to enable interrupts for the data endpoint, - * which services outgoing mouse button and movement reports to the host. If not defined, - * the data endpoint is serviced via polling using the task scheduler. - * * */ diff --git a/Demos/Device/RNDISEthernet/RNDISConstants.h b/Demos/Device/RNDISEthernet/RNDISConstants.h index 3296666f9..ad66f62db 100644 --- a/Demos/Device/RNDISEthernet/RNDISConstants.h +++ b/Demos/Device/RNDISEthernet/RNDISConstants.h @@ -96,4 +96,4 @@ #define OID_802_3_XMIT_ONE_COLLISION 0x01020102UL #define OID_802_3_XMIT_MORE_COLLISIONS 0x01020103UL -#endif \ No newline at end of file +#endif diff --git a/Demos/Host/GenericHIDHost/GenericHIDHost.c b/Demos/Host/GenericHIDHost/GenericHIDHost.c index 9f419ad6d..5ac4257a6 100644 --- a/Demos/Host/GenericHIDHost/GenericHIDHost.c +++ b/Demos/Host/GenericHIDHost/GenericHIDHost.c @@ -182,10 +182,8 @@ void ReadNextReport(void) /* Check to see if a packet has been received */ if (!(Pipe_IsINReceived())) { - #if !defined(INTERRUPT_DATA_PIPE) /* Refreeze HID data IN pipe */ Pipe_Freeze(); - #endif return; } @@ -208,10 +206,8 @@ void ReadNextReport(void) /* Clear the IN endpoint, ready for next data packet */ Pipe_ClearIN(); - #if !defined(INTERRUPT_DATA_PIPE) /* Refreeze HID data IN pipe */ Pipe_Freeze(); - #endif } /** Writes a report to the attached device. @@ -345,43 +341,9 @@ TASK(USB_HID_Host) USB_HostState = HOST_STATE_Ready; break; - #if !defined(INTERRUPT_DATA_PIPE) case HOST_STATE_Ready: ReadNextReport(); break; - #endif } } - -#if defined(INTERRUPT_DATA_PIPE) -/** Interrupt handler for the Endpoint/Pipe interrupt vector. This interrupt fires each time an enabled - * pipe interrupt occurs on a pipe which has had that interrupt enabled. - */ -ISR(ENDPOINT_PIPE_vect, ISR_BLOCK) -{ - /* Save previously selected pipe before selecting a new pipe */ - uint8_t PrevSelectedPipe = Pipe_GetCurrentPipe(); - - /* Check to see if the HID data IN pipe has caused the interrupt */ - if (Pipe_HasPipeInterrupted(HID_DATA_IN_PIPE)) - { - /* Clear the pipe interrupt, and select the data IN pipe */ - Pipe_ClearPipeInterrupt(HID_DATA_IN_PIPE); - Pipe_SelectPipe(HID_DATA_IN_PIPE); - - /* Check to see if the pipe IN interrupt has fired */ - if (USB_INT_HasOccurred(PIPE_INT_IN) && USB_INT_IsEnabled(PIPE_INT_IN)) - { - /* Clear interrupt flag */ - USB_INT_Clear(PIPE_INT_IN); - - /* Read and process the next report from the device */ - ReadNextReport(); - } - } - - /* Restore previously selected pipe */ - Pipe_SelectPipe(PrevSelectedPipe); -} -#endif diff --git a/Demos/Host/GenericHIDHost/GenericHIDHost.txt b/Demos/Host/GenericHIDHost/GenericHIDHost.txt index 41174172a..d72dda103 100644 --- a/Demos/Host/GenericHIDHost/GenericHIDHost.txt +++ b/Demos/Host/GenericHIDHost/GenericHIDHost.txt @@ -47,16 +47,9 @@ * * * - * - * - * - * - * - * - * - * + * * *
Define Name:Location:Description:
INTERRUPT_DATA_ENDPOINTMakefile CDEFSWhen defined, this causes the demo to enable interrupts for the data IN pipe, - * which services reports from the device. If not defined, the data pipe is - * serviced via polling using the task scheduler. + * None + *
*/ diff --git a/Demos/Host/KeyboardHost/KeyboardHost.c b/Demos/Host/KeyboardHost/KeyboardHost.c index f17f950be..628a27314 100644 --- a/Demos/Host/KeyboardHost/KeyboardHost.c +++ b/Demos/Host/KeyboardHost/KeyboardHost.c @@ -180,18 +180,14 @@ void ReadNextReport(void) /* Select keyboard data pipe */ Pipe_SelectPipe(KEYBOARD_DATAPIPE); - #if !defined(INTERRUPT_DATA_PIPE) /* Unfreeze keyboard data pipe */ Pipe_Unfreeze(); - #endif /* Check to see if a packet has been received */ if (!(Pipe_IsINReceived())) { - #if !defined(INTERRUPT_DATA_PIPE) /* Refreeze HID data IN pipe */ Pipe_Freeze(); - #endif return; } @@ -231,15 +227,12 @@ void ReadNextReport(void) putchar(PressedKey); } } - - + /* Clear the IN endpoint, ready for next data packet */ Pipe_ClearIN(); - #if !defined(INTERRUPT_DATA_PIPE) /* Refreeze keyboard data pipe */ Pipe_Freeze(); - #endif } /** Task to set the configuration of the attached device after it has been enumerated, and to read and process @@ -329,53 +322,14 @@ TASK(USB_Keyboard_Host) break; } - #if defined(INTERRUPT_DATA_PIPE) - /* Select and unfreeze keyboard data pipe */ - Pipe_SelectPipe(KEYBOARD_DATAPIPE); - Pipe_Unfreeze(); - #endif - puts_P(PSTR("Keyboard Enumerated.\r\n")); USB_HostState = HOST_STATE_Ready; break; - #if !defined(INTERRUPT_DATA_PIPE) case HOST_STATE_Ready: /* If a report has been received, read and process it */ ReadNextReport(); break; - #endif } } - -#if defined(INTERRUPT_DATA_PIPE) -/** Interrupt handler for the Endpoint/Pipe interrupt vector. This interrupt fires each time an enabled - * pipe interrupt occurs on a pipe which has had that interrupt enabled. - */ -ISR(ENDPOINT_PIPE_vect, ISR_BLOCK) -{ - /* Save previously selected pipe before selecting a new pipe */ - uint8_t PrevSelectedPipe = Pipe_GetCurrentPipe(); - - /* Check to see if the keyboard data pipe has caused the interrupt */ - if (Pipe_HasPipeInterrupted(KEYBOARD_DATAPIPE)) - { - /* Clear the pipe interrupt, and select the keyboard pipe */ - Pipe_ClearPipeInterrupt(KEYBOARD_DATAPIPE); - Pipe_SelectPipe(KEYBOARD_DATAPIPE); - - /* Check to see if the pipe IN interrupt has fired */ - if (USB_INT_HasOccurred(PIPE_INT_IN) && USB_INT_IsEnabled(PIPE_INT_IN)) - { - /* Clear interrupt flag */ - USB_INT_Clear(PIPE_INT_IN); - - /* Read and process the next report from the device */ - ReadNextReport(); - } - - /* Restore previously selected pipe */ - Pipe_SelectPipe(PrevSelectedPipe); -} -#endif diff --git a/Demos/Host/KeyboardHost/KeyboardHost.txt b/Demos/Host/KeyboardHost/KeyboardHost.txt index 455c2d28b..a3d5f717d 100644 --- a/Demos/Host/KeyboardHost/KeyboardHost.txt +++ b/Demos/Host/KeyboardHost/KeyboardHost.txt @@ -56,16 +56,9 @@ * * * - * - * - * - * - * - * - * - * + * * *
Define Name:Location:Description:
INTERRUPT_DATA_ENDPOINTMakefile CDEFSWhen defined, this causes the demo to enable interrupts for the data pipe, - * which services reports from the device. If not defined, the data pipe is - * serviced via polling using the task scheduler. + * None + *
*/ diff --git a/Demos/Host/MouseHost/MouseHost.c b/Demos/Host/MouseHost/MouseHost.c index 3c858a890..77db55282 100644 --- a/Demos/Host/MouseHost/MouseHost.c +++ b/Demos/Host/MouseHost/MouseHost.c @@ -181,18 +181,14 @@ void ReadNextReport(void) /* Select mouse data pipe */ Pipe_SelectPipe(MOUSE_DATAPIPE); - #if !defined(INTERRUPT_DATA_PIPE) /* Unfreeze keyboard data pipe */ Pipe_Unfreeze(); - #endif /* Check to see if a packet has been received */ if (!(Pipe_IsINReceived())) { - #if !defined(INTERRUPT_DATA_PIPE) /* Refreeze HID data IN pipe */ Pipe_Freeze(); - #endif return; } @@ -230,10 +226,8 @@ void ReadNextReport(void) /* Clear the IN endpoint, ready for next data packet */ Pipe_ClearIN(); - #if !defined(INTERRUPT_DATA_PIPE) /* Refreeze mouse data pipe */ Pipe_Freeze(); - #endif } /** Task to set the configuration of the attached device after it has been enumerated, and to read and process @@ -324,54 +318,14 @@ TASK(USB_Mouse_Host) break; } - #if defined(INTERRUPT_DATA_PIPE) - /* Select and unfreeze mouse data pipe */ - Pipe_SelectPipe(MOUSE_DATAPIPE); - Pipe_Unfreeze(); - #endif - puts_P(PSTR("Mouse Enumerated.\r\n")); USB_HostState = HOST_STATE_Ready; break; - #if !defined(INTERRUPT_DATA_PIPE) case HOST_STATE_Ready: /* If a report has been received, read and process it */ ReadNextReport(); break; - #endif - } -} - -#if defined(INTERRUPT_DATA_PIPE) -/** Interrupt handler for the Endpoint/Pipe interrupt vector. This interrupt fires each time an enabled - * pipe interrupt occurs on a pipe which has had that interrupt enabled. - */ -ISR(ENDPOINT_PIPE_vect, ISR_BLOCK) -{ - /* Save previously selected pipe before selecting a new pipe */ - uint8_t PrevSelectedPipe = Pipe_GetCurrentPipe(); - - /* Check to see if the mouse data pipe has caused the interrupt */ - if (Pipe_HasPipeInterrupted(MOUSE_DATAPIPE)) - { - /* Clear the pipe interrupt, and select the mouse pipe */ - Pipe_ClearPipeInterrupt(MOUSE_DATAPIPE); - Pipe_SelectPipe(MOUSE_DATAPIPE); - - /* Check to see if the pipe IN interrupt has fired */ - if (USB_INT_HasOccurred(PIPE_INT_IN) && USB_INT_IsEnabled(PIPE_INT_IN)) - { - /* Clear interrupt flag */ - USB_INT_Clear(PIPE_INT_IN); - - /* Read and process the next report from the device */ - ReadNextReport(); - } } - - /* Restore previously selected pipe */ - Pipe_SelectPipe(PrevSelectedPipe); } -#endif diff --git a/Demos/Host/MouseHost/MouseHost.txt b/Demos/Host/MouseHost/MouseHost.txt index 118ca9d8a..3838a7011 100644 --- a/Demos/Host/MouseHost/MouseHost.txt +++ b/Demos/Host/MouseHost/MouseHost.txt @@ -57,16 +57,9 @@ * * * - * - * - * - * - * - * - * - * + * * *
Define Name:Location:Description:
INTERRUPT_DATA_ENDPOINTMakefile CDEFSWhen defined, this causes the demo to enable interrupts for the data pipe, - * which services reports from the device. If not defined, the data pipe is - * serviced via polling using the task scheduler. + * None + *
*/ diff --git a/Demos/OTG/TestApp/TestEvents.c b/Demos/OTG/TestApp/TestEvents.c index 884e5b680..b542bfc24 100644 --- a/Demos/OTG/TestApp/TestEvents.c +++ b/Demos/OTG/TestApp/TestEvents.c @@ -175,6 +175,8 @@ EVENT_HANDLER(USB_DeviceEnumerationFailed) { puts_P(PSTR(ESC_BG_RED "Dev Enum Error\r\n")); printf_P(PSTR(" -- Error Code %d\r\n"), ErrorCode); + printf_P(PSTR(" -- Sub Error Code %d\r\n"), SubErrorCode); + printf_P(PSTR(" -- In State %d\r\n"), USB_HostState); } /** diff --git a/LUFA.pnproj b/LUFA.pnproj index dae734b10..4e78e5be0 100644 --- a/LUFA.pnproj +++ b/LUFA.pnproj @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/LUFA/ChangeLog.txt b/LUFA/ChangeLog.txt index cc198089c..1833596f3 100644 --- a/LUFA/ChangeLog.txt +++ b/LUFA/ChangeLog.txt @@ -11,6 +11,8 @@ * - Fixed bug in RNDISEthernet and DualCDC demos not using the correct USB_ControlRequest structure for control request data * - Fixed documentation showing incorrect USB mode support on the supported AVRs list * - Fixed RNDISEthernet not working under Linux due to Linux requiring an "optional" request which was unhandled + * - Fixed Mouse and Keyboard device demos not acting in accordance with the HID specification for idle periods (thanks to Brian Dickman) + * - Removed support for endpoint/pipe non-control interrupts; these did not act in the way users expected, and had many subtle issues * * * \section Sec_ChangeLog090510 Version 090510 diff --git a/LUFA/Drivers/USB/LowLevel/Endpoint.h b/LUFA/Drivers/USB/LowLevel/Endpoint.h index aa5005a82..4882acc3b 100644 --- a/LUFA/Drivers/USB/LowLevel/Endpoint.h +++ b/LUFA/Drivers/USB/LowLevel/Endpoint.h @@ -153,34 +153,6 @@ * \see \ref ENDPOINT_PIPE_vect for more information on the common pipe and endpoint interrupt vector. */ #define ENDPOINT_INT_SETUP UEIENX, (1 << RXSTPE), UEINTX, (1 << RXSTPI) - - /** Interrupt definition for the endpoint IN interrupt (for INTERRUPT type endpoints). Should be - * used with the USB_INT_* macros located in USBInterrupt.h. - * - * This interrupt will fire if enabled on an INTERRUPT type endpoint if a the endpoint interrupt - * period has elapsed and the endpoint is ready for a new packet to be written to its FIFO buffer - * (if required). - * - * \note This interrupt must be enabled and cleared on *each* endpoint which requires it (after the - * endpoint is selected), and will fire the common endpoint interrupt vector. - * - * \see \ref ENDPOINT_PIPE_vect for more information on the common pipe and endpoint interrupt vector. - */ - #define ENDPOINT_INT_IN UEIENX, (1 << TXINE) , UEINTX, (1 << TXINI) - - /** Interrupt definition for the endpoint OUT interrupt (for INTERRUPT type endpoints). Should be - * used with the USB_INT_* macros located in USBInterrupt.h. - * - * This interrupt will fire if enabled on an INTERRUPT type endpoint if a the endpoint interrupt - * period has elapsed and the endpoint is ready for a packet from the host to be read from its - * FIFO buffer (if received). - * - * \note This interrupt must be enabled and cleared on *each* endpoint which requires it (after the - * endpoint is selected), and will fire the common endpoint interrupt vector. - * - * \see \ref ENDPOINT_PIPE_vect for more information on the common pipe and endpoint interrupt vector. - */ - #define ENDPOINT_INT_OUT UEIENX, (1 << RXOUTE), UEINTX, (1 << RXOUTI) /* Pseudo-Function Macros: */ #if defined(__DOXYGEN__) @@ -265,13 +237,6 @@ */ static inline uint8_t Endpoint_GetEndpointInterrupts(void); - /** Clears the endpoint interrupt flag. This clears the specified endpoint number's interrupt - * mask in the endpoint interrupt flag register. - * - * \param EndpointNumber Index of the endpoint whose interrupt flag should be cleared - */ - static inline void Endpoint_ClearEndpointInterrupt(uint8_t EndpointNumber); - /** Determines if the specified endpoint number has interrupted (valid only for INTERRUPT type * endpoints). * @@ -398,8 +363,6 @@ #define Endpoint_GetEndpointInterrupts() UEINT - #define Endpoint_ClearEndpointInterrupt(n) MACROS{ UEINT &= ~(1 << n); }MACROE - #define Endpoint_HasEndpointInterrupted(n) ((UEINT & (1 << n)) ? true : false) #define Endpoint_IsINReady() ((UEINTX & (1 << TXINI)) ? true : false) diff --git a/LUFA/Drivers/USB/LowLevel/HostChapter9.c b/LUFA/Drivers/USB/LowLevel/HostChapter9.c index ee51cf3ae..4b96c691d 100644 --- a/LUFA/Drivers/USB/LowLevel/HostChapter9.c +++ b/LUFA/Drivers/USB/LowLevel/HostChapter9.c @@ -155,7 +155,7 @@ static uint8_t USB_Host_Wait_For_Setup_IOS(const uint8_t WaitType) { uint16_t TimeoutCounter = USB_HOST_TIMEOUT_MS; - while (!(((WaitType == USB_HOST_WAITFOR_SetupSent) && Pipe_IsSETUPSent()) || + while (!(((WaitType == USB_HOST_WAITFOR_SetupSent) && Pipe_IsSETUPSent()) || ((WaitType == USB_HOST_WAITFOR_InReceived) && Pipe_IsINReceived()) || ((WaitType == USB_HOST_WAITFOR_OutReady) && Pipe_IsOUTReady()))) { diff --git a/LUFA/Drivers/USB/LowLevel/Pipe.h b/LUFA/Drivers/USB/LowLevel/Pipe.h index 7e81cf686..d5c209492 100644 --- a/LUFA/Drivers/USB/LowLevel/Pipe.h +++ b/LUFA/Drivers/USB/LowLevel/Pipe.h @@ -158,34 +158,6 @@ */ #define PIPE_EPSIZE_MASK 0x7FF - /** Interrupt definition for the pipe IN interrupt (for INTERRUPT type pipes). Should be used with - * the USB_INT_* macros located in USBInterrupt.h. - * - * This interrupt will fire if enabled on an INTERRUPT type pipe if the pipe interrupt period has - * elapsed and the pipe is ready for the next packet from the attached device to be read out from its - * FIFO buffer (if received). - * - * \note This interrupt must be enabled and cleared on *each* pipe which requires it (after the pipe - * is selected), and will fire the common pipe interrupt vector. - * - * \see \ref ENDPOINT_PIPE_vect for more information on the common pipe and endpoint interrupt vector. - */ - #define PIPE_INT_IN UPIENX, (1 << RXINE) , UPINTX, (1 << RXINI) - - /** Interrupt definition for the pipe OUT interrupt (for INTERRUPT type pipes). Should be used with - * the USB_INT_* macros located in USBInterrupt.h. - * - * This interrupt will fire if enabled on an INTERRUPT type endpoint if a the pipe interrupt period - * has elapsed and the pipe is ready for a packet to be written to the pipe's FIFO buffer and sent - * to the attached device (if required). - * - * \note This interrupt must be enabled and cleared on *each* pipe which requires it (after the pipe - * is selected), and will fire the common pipe interrupt vector. - * - * \see \ref ENDPOINT_PIPE_vect for more information on the common pipe and endpoint interrupt vector. - */ - #define PIPE_INT_OUT UPIENX, (1 << TXOUTE), UPINTX, (1 << TXOUTI) - /** Interrupt definition for the pipe SETUP bank ready interrupt (for CONTROL type pipes). Should be * used with the USB_INT_* macros located in USBInterrupt.h. * @@ -337,12 +309,6 @@ */ static inline uint8_t Pipe_GetPipeInterrupts(void); - /** Clears the interrupt flag for the specified pipe number. - * - * \param PipeNumber Index of the pipe whose interrupt flag is to be cleared - */ - static inline void Pipe_ClearPipeInterrupt(uint8_t PipeNumber); - /** Determines if the specified pipe number has interrupted (valid only for INTERRUPT type * pipes). * @@ -504,8 +470,6 @@ #define Pipe_GetPipeInterrupts() UPINT - #define Pipe_ClearPipeInterrupt(n) MACROS{ UPINT &= ~(1 << n); }MACROE - #define Pipe_HasPipeInterrupted(n) ((UPINT & (1 << n)) ? true : false) #define Pipe_Unfreeze() MACROS{ UPCONX &= ~(1 << PFREEZE); }MACROE diff --git a/LUFA/MigrationInformation.txt b/LUFA/MigrationInformation.txt index 891c5b273..d7eb2dfcc 100644 --- a/LUFA/MigrationInformation.txt +++ b/LUFA/MigrationInformation.txt @@ -12,6 +12,16 @@ * * \section Sec_MigrationXXXXXX Migrating from 090510 to XXXXXX * + * Device Mode + * - Support for non-control data endpoint interrupts has been dropped due to many issues in the implementation. All existing + * projects using interrupts on non-control endpoints should switch to polling. + * - The Endpoint_ClearEndpointInterrupt() macro has been deleted and references to it should be removed. + * + * Device Mode + * - Support for non-control data pipe interrupts has been dropped due to many issues in the implementation. All existing + * projects using interrupts on non-control pipes should switch to polling. + * - The Pipe_ClearPipeInterrupt() macro has been deleted and references to it should be removed. + * * * \section Sec_Migration090510 Migrating from 090401 to 090510 * -- cgit v1.2.3